2

onDrawカスタムビューの方法で キャンバスにマトリックスを設定し、canvas.setMatrix(matrix);定義済みのペイントを使用してグリッドを描画します。

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 倍ずれています。なぜこれが起こっているのか、それを修正する方法はありますか? ちなみに、マトリックスは初期化されていないため、ドキュメントによると、IDであると想定されています。

どうもありがとう!

4

2 に答える 2

7

Matrixこの動作を、 aViewのキャンバスの元がビューの位置によって既に変換されているということに絞り込みました。Matrixただし、使用してCanvas.getMatrix()、またはを取得した場合、これは明らかではありませんView.getMatrix()。これらの呼び出しから恒等行列を取得します。

表示されているキャンバスのオフセットViewは、画面の上部 (ステータス バー、タイトル バーなど) からの のオフセットとまったく同じ高さである可能性が最も高いです。

このユースケース、およびほとんどのユースケースでcanvas.concat(matrix)代わりに使用することは正しいです。canvas.setMatrix(matrix)元のマトリックスが本当に必要な場合は、デバッグ時に行ったので、 をView独自に翻訳して手動で変換する必要がありWindowます。

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

コメントで追加の質問に答えるために編集します。

タッチ座標 (または任意の画面座標) を a の座標に一致するように変換するには、代わりにCanvasすべての変換を に行い、そのマトリックスを使用して各フレームを描画します。(または、現在行っているようにすべての変換を直接実行し続け、各描画後にマトリックスを取得するために使用することもできます。非推奨ですが、機能します。)MatrixCanvas.concat()CanvasCanvas.getMatrix(mMyMatrix)

次に、マトリックスを使用して、元のグリッド境界を画面に描画されたものに変換できます。基本的に、グリッドを描画するときとまったく同じことをCanvas行っており、グリッドのコーナー ポイントを画面座標に変換しています。グリッドは、タッチ イベントと同じ座標系になります。

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();
}

または、マトリックスを取得するための非推奨の方法です。これはまだ機能しており、おそらく変更が少なくて済みます。

@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();
}
于 2013-06-17T08:00:39.967 に答える
1

問題の原因ではないにしても、この問題の解決策を見つけました。

行を に置き換えるcanvas.setMatrix(matrix);canvas.concat(matrix);うまくいきました。マトリックスを設定すると、ビューではなく画面の高さと幅に関して計算されるキャンバスの原点が変更されるという事実に部分的に関係していたと思います。しかし、これは私が抱えていた他のいくつかの問題も魔法のように解決したため、謎があります.

編集

この方法で物事を行うことの結果の 1 つはevent.getX()、メソッドevent.getY()内でonTouchEvent(MotionEvent event)扱いにくい整数を返し始めることです。私のカスタムビューは、クリックして正方形の座標を取得できる、ズーム可能でパン可能な正方形のグリッドを作成するためのものです。このメソッドを使用して、クリック イベントの (x,y) 座標を取得しようとします (MotionEvent.ACTION_UPケース インonTouchEventメソッド)。

たとえば、次の方法でx座標を取得しようとします

int x = (int) ((start.x - dspl.x)/(cellWidth*scaleFactor));

画面をパンした量 (dsplこれまでに発生した変位の合計を示します) とズームした量 (scaleFactor発生したスケーリングの合計を示します) を説明します。ただし、これは、連続してズームが発生したポイントを考慮していません。

正しい座標を取得する方法について何か良いアイデアはありますか?

于 2013-06-17T06:35:03.467 に答える