如何在缩放时保持平移/缩放Android布局中的焦点?

时间:2016-04-19 19:19:25

标签: java android

我有一个扩展FrameLayout的自定义布局,几乎支持我需要的一切。滚动和缩放子视图或布局效果很好。但我遇到的一件事就是在缩放时保持焦点。捏指之间的中心点离开屏幕,但我希望它能像谷歌地图应用程序那样保持焦点(中心)点。

这是代码。

public class BetterZoomLayout extends FrameLayout
{

// State objects and values related to gesture tracking.
private ScaleGestureDetector mScaleGestureDetector;
private GestureDetectorCompat mGestureDetector;
private static final float MIN_ZOOM = 1.0f;
private static final float MAX_ZOOM = 4.0f;

private float scale = 1.0f;
private float lastScaleFactor = 0f;
// How much to translate the canvas
private float distanceX = 0f;
private float distanceY = 0f;

public BetterZoomLayout(Context context)
    {
    super(context);
    init(context);
    }

public BetterZoomLayout(Context context, AttributeSet attrs)
    {
    super(context, attrs);
    init(context);
    }

public BetterZoomLayout(Context context, AttributeSet attrs, int defStyle)
    {
    super(context, attrs, defStyle);
    init(context);
    }

private void init(Context context)
    {
    // Sets up interactions
    mScaleGestureDetector = new ScaleGestureDetector(context, mScaleGestureListener);
    mGestureDetector = new GestureDetectorCompat(context, mGestureListener);
    }

@Override
public boolean onTouchEvent(MotionEvent event)
    {
    boolean retVal = mScaleGestureDetector.onTouchEvent(event);
    retVal = mGestureDetector.onTouchEvent(event) || retVal;
    applyScaleAndTranslation();
    return retVal || super.onTouchEvent(event);
    }

/**
 * The scale listener, used for handling multi-finger scale gestures.
 */
private final ScaleGestureDetector.OnScaleGestureListener mScaleGestureListener
        = new ScaleGestureDetector.SimpleOnScaleGestureListener()
    {
    /**
     * This is the active focal point in terms of the viewport. Could be a local
     * variable but kept here to minimize per-frame allocations.
     */

    @Override
    public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector)
        {
        lastScaleFactor = 0f;
        return true;
        }

    @Override
    public boolean onScale(ScaleGestureDetector scaleGestureDetector)
        {
        float scaleFactor = scaleGestureDetector.getScaleFactor();

        if (lastScaleFactor == 0 || (Math.signum(scaleFactor) == Math.signum(lastScaleFactor)))
            {
            scale *= scaleFactor;
            scale = Math.max(MIN_ZOOM, Math.min(scale, MAX_ZOOM));
            lastScaleFactor = scaleFactor;
            }
        else
            {
            lastScaleFactor = 0;
            }

        return true;
        }
    };

/**
 * The gesture listener, used for handling simple gestures such as double touches, scrolls,
 * and flings.
 */
private final GestureDetector.SimpleOnGestureListener mGestureListener
        = new GestureDetector.SimpleOnGestureListener()
    {
    @Override
    public boolean onDown(MotionEvent e)
        {
        return true;
        }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float dX, float dY)
        {
        setupTranslation(dX, dY);
        return true;
        }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
        {
        //fling((int) -velocityX, (int) -velocityY);
        return true;
        }
    };



private void setupTranslation(float dX, float dY)
    {
    distanceX = -1 * dX + distanceX;
    distanceY = -1 * dY + distanceY;
    getParent().requestDisallowInterceptTouchEvent(true);
    Rect viewableRect = new Rect();
    BetterZoomLayout.this.getDrawingRect(viewableRect);
    float offscreenWidth = child().getWidth() - (viewableRect.right - viewableRect.left);
    float offscreenHeight = child().getHeight() - (viewableRect.bottom - viewableRect.top);
    float maxDx = (child().getWidth() - (child().getWidth() / scale)) / 2 * scale;
    float maxDy = (child().getHeight() - (child().getHeight() / scale)) / 2 * scale;
    distanceX = Math.min(Math.max(distanceX, -(maxDx + offscreenWidth)), maxDx);
    distanceY = Math.min(Math.max(distanceY, -(maxDy + offscreenHeight)), maxDy);
    }

private void applyScaleAndTranslation()
    {
    child().setScaleX(scale);
    child().setScaleY(scale);
    child().setTranslationX(distanceX);
    child().setTranslationY(distanceY);
    }

private View child()
    {
    return getChildAt(0);
    }
}

0 个答案:

没有答案