Android Canvas ScaleFocus causing jumping position

寵の児 提交于 2020-01-06 20:08:59

问题


I am working on a game that will be looking down onto a grid moving pieces around (similar to Chess). I want the user to be able to pan and zoom the map. I have been making transformations to a matrix, and then concatenating those changes to the canvas matrix. While it's mostly working, I have a weird bug:

After the initial scale, if I pinch to scale again, the screen jumps (it's as if a swiped somewhere else and it moved there instantly) and then scales smoothly. I have narrowed this behavior down to the scaleFocus variables of the scale function

canvas.scale(scaleFactor, scaleFactor, scaleFocusX, scaleFocusY);

If I set scaleFocusX and scaleFocusY to 0, the always use the origin as the scale focus and the jumping does not occur. However, using the origin is not practical as you scroll farther from it. Here is a summary of my code.

public void onDraw(Canvas canvas) {
  ...
  canvas.translate(-mPosX, -mPosY);
  canvas.scale(scaleFactor, scaleFactor, scaleFocusX, scaleFocusY);

  //Create an inverse of the tranformation matrix, to be used when determining click location.
  canvas.getMatrix().invert(canvasMatrix);
  ... }


public class MyOnScaleGestureListener extends
        ScaleGestureDetector.SimpleOnScaleGestureListener {

    @Override
    public boolean onScale(ScaleGestureDetector detector) {

        scaleFactor *= detector.getScaleFactor();
        // Don't let the object get too small or too large.
        scaleFactor = Math.max(MIN_SCALE, Math.min(scaleFactor, MAX_SCALE));
        return true;
    }

    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        Point scaleFocus = calculateClickAbsoluteLocation
                (detector.getFocusX(), detector.getFocusY());
        scaleFocusX = scaleFocus.x;
        scaleFocusY = scaleFocus.y;
        return true;
    }

    @Override
    public void onScaleEnd(ScaleGestureDetector detector) {

    }


//This method will take point on the phone screen, and convert it to be
//a point on the canvas (since the canvas area is larger than the screen).
public Point calculateClickAbsoluteLocation(float x, float y) {
    Point result = new Point();
    float[] coordinates = {x, y};

    //MapPoints will essentially convert the click coordinates from "screen pixels" into
    //"canvas pixels", so you can determine what tile was clicked.
    canvasMatrix.mapPoints(coordinates);

    result.set((int)coordinates[0], (int)coordinates[1]);
    return result;
}

回答1:


First of all, instead of using float[] coordinates = {x, y}; you better use PointF coordinates = new PointF(x, y);, then you can get x and y with coordinates.x and coordinates.y.

Your problem is that when scaling you still handle the touch events (so touch is handled twice).

We need a global variable that tells whether we are scaling or not: boolean scaling = false

So, in OnTouchEvent you should check it:

@Override
    public boolean onTouchEvent(@NonNull MotionEvent event) { 
        detector.onTouchEvent(event);
        if (detector.isInProgress()) 
            scaling = true;

Release with: if (event.getAction() == MotionEvent.ACTION_UP) { scaling = false;

And all of your code in onTouchEvent that works with clicks should be surrounded with

if (!scaling) { ... }


来源:https://stackoverflow.com/questions/35216036/android-canvas-scalefocus-causing-jumping-position

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!