画布是由自定义视图中的onDraw设置单位矩阵偏移 [英] canvas is offset by setting identity matrix in onDraw of custom view

查看:188
本文介绍了画布是由自定义视图中的onDraw设置单位矩阵偏移的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我设置一个矩阵来我在通过自定义视图的的onDraw 帆布方法
canvas.setMatrix(矩阵); 然后我就用predefined油漆绘制网格:

I set a matrix to my canvas in the onDraw method of a custom view via canvas.setMatrix(matrix); then I just draw a grid using predefined paints:

canvas.drawRect(0,0,viewWidth,viewHeight, background);

for(int i=0; i <= nRows; i++){
    canvas.drawLine(0,i*cellHeight, nCols*cellWidth,i*cellHeight,lines);
    canvas.drawLine(i*cellWidth, 0, i*cellWidth, nRows*cellHeight, lines);
    if(i != nRows)
        canvas.drawText(""+i, i*cellWidth, (i+1)*cellHeight, text);
}

和由于某种原因,整个印刷品被细胞的约1.5倍的高度偏移。任何想法,为什么这种情况正在发生或如何解决呢?基质未初始化并且根据文档应该因此被标识,顺便

and for some reason the whole canvas is offset by about 1.5 times the height of a cell. Any idea why this is happening or how to fix it? The matrix was not initialized and according to the documentation is supposed to therefore be the identity, by the way.

非常感谢!

推荐答案

我已经缩小这种行为降低到原来的矩阵查看的帆布已经由视图的位置转换。这不是很明显,但是,如果你得到的矩阵使用 Canvas.getMatrix() View.getMatrix()。你会得到这些电话矩阵。

I've narrowed this behavior down to that the original Matrix of a View's canvas is already translated by the position of the view. This is not apparent, however, if you get the Matrix using Canvas.getMatrix(), or View.getMatrix(). You'll get the identity matrix from those calls.

画布抵消你看到的很可能是完全一样的高度了查看的从屏幕顶部的偏移量(状态栏,标题栏等)

The canvas offset you're seeing is most likely exactly the same height as the View's offset from the top of the screen (Status Bar, Title Bar etc).

您是在本使用 canvas.concat(矩阵)而不是 canvas.setMatrix(矩阵)正确使用的情况下,大多数用例。如果你真的需要原始矩阵,我做了调试时,必须手动由查看的在自己的窗口

You are correct in using canvas.concat(matrix) instead of canvas.setMatrix(matrix) in this use case, and most use cases. If you really need the original matrix, I did when debugging, you must transform it manually by the View's translation in its own Window:

int[] viewLocation = new int[2];
mView.getLocationInWindow(viewLocation);
mOriginalMatrix.setTranslate(viewLocation[0], viewLocation[1]);

修改以回答评论额外的问题:

EDIT to answer the additional question in comments:

要变换触摸坐标(或任何屏幕坐标),以匹配的画布,简单地让所有的转换到矩阵,而是和 Canvas.concat()与矩阵前绘制每一帧。 (或者你可以直接保存所做的一切转变为画布像你现在正在做的,并使用 Canvas.getMatrix(mMyMatrix)来检索每个战平后矩阵,它是pcated德$ p $,但它的工作原理。)

To transform touch coordinates (or any screen coordinates) to match those of a Canvas, simply make all the transformations to a Matrix instead, and Canvas.concat() with that matrix each frame before drawing. (Or you could keep doing all the transformations directly to Canvas like you're doing now, and use Canvas.getMatrix(mMyMatrix) to retrieve the matrix after each draw. It's deprecated but it works.)

该矩阵可以用来到原来的网格边界转换为那些在屏幕上绘制。你基本上做同样的事情画布时,它绘制电网,改造电网的角点到屏幕坐标在做什么。网格现在将是相同的坐标系中作为触摸事件

The matrix can then be used to convert your original grid bounds to those that are drawn on screen. You're essentially doing the exact same thing as Canvas is doing when it draws the grid, transforming the corner points of the grid to screen coordinates. The grid will now be in the same coordinate system as your touch events:

private final Matrix mMyMatrix = new Matrix();

// Assumes that the grid covers the whole View.
private final float[] mOriginalGridCorners = new float[] {
    0, 0,                   // top left (x, y)
    getWidth(), getHeight() // bottom right (x, y)
};

private final float[] mTransformedGridCorners = new float[4];

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (/* User pans the screen */) {
        mMyMatrix.postTranslate(deltaX, deltaY);
    }

    if (/* User zooms the screen */) {
        mMyMatrix.postScale(deltaScale, deltaScale);
    }

    if (/* User taps the grid */) {
        // Transform the original grid corners to where they
        // are on the screen (panned and zoomed).
        mMyMatrix.mapPoints(mTransformedGridCorners, mOriginalGridCorners);
        float gridWidth = mTransformedGridCorners[2] - mTransformedGridCorners[0];
        float gridHeight = mTransformedGridCorners[3] - mTransformedGridCorners[1];
        // Get the x and y coordinate of the tap inside the
        // grid, between 0 and 1.
        float x = (event.getX() - mTransformedGridCorners[0]) / gridWidth;
        float y = (event.getY() - mTransformedGridCorners[1]) / gridHeight;
        // To get the tapped grid cell.
        int column = (int)(x * nbrColumns);
        int row = (int)(y * nbrRows);
        // Or to get the tapped exact pixel in the original grid.
        int pixelX = (int)(x * getWidth());
        int pixelY = (int)(y * getHeight());
    }
    return true;
}

@Override
protected void onDraw(Canvas canvas) {
    // Each frame, transform your canvas with the matrix.
    canvas.save();
    canvas.concat(mMyMatrix);
    // Draw grid.
    grid.draw(canvas);
    canvas.restore();
}

或者去precated的方式来获得的矩阵,这仍有效,或许会需要更少的变化:

Or the deprecated way to get the matrix, which still works and would perhaps require less changes:

@Override
protected void onDraw(Canvas canvas) {
    canvas.save();
    // Transform canvas and draw the grid.
    grid.draw(canvas);
    // Get the matrix from canvas. Can be used to transform
    // corners on the next touch event.
    canvas.getMatrix(mMyMatrix);
    canvas.restore();
}

这篇关于画布是由自定义视图中的onDraw设置单位矩阵偏移的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆