2

キャンバス上にドットを描画します。これはズームインまたはズームアウトできます。

私の知る限り、描画関数canvas.drawCircle()はキャンバス座標系の座標を取り込みます。さらに、キャンバスをズームしても座標は変わりません。

たとえば、以前(50, 50)にキャンバス座標系でドットを描画してから、キャンバスを拡大しても、キャンバス内のドットの座標はそのまま(50, 50)です。しかし、明らかに、ドットは画面に対して移動されています。

キャンバスがズームされている場合、ドットは画面上の同じ位置に保持する必要があります。*つまり、ドットが画面に対して移動した後、画面に対して元の位置に戻します。*

私のonDraw()機能は次のとおりです。

@Override
public void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    canvasWidth = canvas.getWidth();
    canvasHeight = canvas.getHeight();

    canvas.save();
    canvas.translate(mPosX, mPosY);
    canvas.scale(mScaleFactor, mScaleFactor);
    mImage.draw(canvas); // draw the map as the background

            Paint PointStyle = new Paint();
    PointStyle.setColor(Color.BLUE);
    PointStyle.setStyle(Paint.Style.FILL_AND_STROKE);
    PointStyle.setStrokeWidth(2);

    canvas.drawCircle(Constant.INITIAL_X, Constant.INITIAL_Y, 3, PointStyle);

    canvas.restore();
}

スケーリング後にドットを画面に戻すには、次の方法を試しました。

private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
    @Override
    public boolean onScale(ScaleGestureDetector detector) {

        mScaleFactor *= detector.getScaleFactor(); // accumulate the scale factors
        // Don't let the object get too small or too large.
        mScaleFactor = Math.max(1f, Math.min(mScaleFactor, 10.0f)); // 1 ~ 10

        float pinToCornerOnScreenXDistance = 0;
        float pinToCornerOnScreenYDistance = 0;
        float canvasToScreenDiffRatioX = 0;
        float canvasToScreenDiffRatioY = 0;
        float pinOnCanvasX = 0;
        float pinOnCanvasY = 0;

        // pin's location on the screen --> S:(336, 578)
        pinToCornerOnScreenXDistance = 336 - canvasLeftTopCornerOnScreenX;
        pinToCornerOnScreenYDistance = 578 - canvasLeftTopCornerOnScreenY;
        Log.d("Screen Diff", "X: " + pinToCornerOnScreenXDistance + " Y: " + pinToCornerOnScreenYDistance);

        canvasToScreenDiffRatioX = canvasWidth * mScaleFactor / 720; // screen of HTC One X --> 720*1280
        canvasToScreenDiffRatioY = canvasHeight * mScaleFactor / 1280;
        Log.d("Ratio", canvasToScreenDiffRatioX + " " + canvasToScreenDiffRatioY);

        pinOnCanvasX = 0 + pinToCornerOnScreenXDistance * canvasToScreenDiffRatioX; // canvas left top corner is the origin (0, 0)
        pinOnCanvasY = 0 + pinToCornerOnScreenYDistance * canvasToScreenDiffRatioY;
        Log.d("Pin on Canvas", "X: " + pinOnCanvasX + " Y: " + pinOnCanvasY);

        Constant.setInitialX(pinOnCanvasX);
        Constant.setInitialY(pinOnCanvasY);
        historyXSeries.set(0, Constant.INITIAL_X);
        historyYSeries.set(0, Constant.INITIAL_Y);

        invalidate();
        return true;
    }
}

このアイデアは、キャンバスをズームインまたはズームアウトしても、左上隅が動かないことに気付いたという事実に基づいています。つまり、キャンバスの一番上の角がズームの中心です。

次に、キャンバスが移動したときに、ズーム中心の座標を正常に更新し続けます。このように、キャンバスを移動したりズームしたりしても、常にズーム中心の座標が と にcanvasLeftTopCornerOnScreenXありcanvasLeftTopCornerOnScreenYます。

次に、スケーリング中に移動したことのないズーム中心と、ここでドットを配置したい目的の位置との間の距離を利用しようとし(336, 578)ます。として計算しpinToCornerOnScreenDistanceます。

その名の通り画面上の距離です。描画関数はスクリーン座標系ではなくキャンバス座標系に基づいているため、ドットを描画できるようにキャンバス距離にスケーリングする必要があります。現在、コードはデバイス固有です。つまり、現時点では 1280*720 の画面を持つ HTC One X 専用です。したがって、次のようにスケーリングを行います。

canvasToScreenDiffRatioX = canvasWidth * mScaleFactor / 720;
canvasToScreenDiffRatioY = canvasHeight * mScaleFactor / 1280;

次に、最後に、画面上のポイントの新しいキャンバス上の座標を計算し、(336, 578)そこにドットを描画します。

しかし、結果は正しくありません。キャンバスをズームすると、描画した点が(336, 578)画面上に表示されません。

どこが悪いのか誰か教えてもらえますか?または、これを行う別の方法を提案しますか?

コメントや回答は大歓迎です!

4

2 に答える 2

1

アプリはフルスクリーンを使用していますか? それ以外の場合、高さは 1280 ではありません。しかし、それはあなたの問題ではないと思います。

私の理解に基づいて、コードを次のように変更します

pinOnCanvasX = 336 / mScaleFactor;
pinOnCanvasY = 578 / mScaleFactor;

mScaleFactor == 1の場合、キャンバス上のピンが画面上で同じであると仮定します

于 2013-07-12T05:37:20.350 に答える
0

これを試してみてください。これはあなたの問題に役立つと思います。

pinOnCanvasX = (336 * mScaleFactor) + trans_x;

pinOnCanvasY = (578 * mScaleFactor) + trans_y;

here, trans_x and trans_y is translation of canvas on x and y axis. here in your case should be mPosX, mPosY but not sure what these points means for.

共有したい方法は、キャンバスと同じように、円の開始点を拡大縮小して変換することです。つまり、キャンバスが何らかの値でスケーリングおよび変換された場合、開始点にも同じ値が適用されます。

これで問題が解決することを願っています。

于 2013-07-12T10:04:48.393 に答える