矩阵翻译和缩放

时间:2016-03-20 01:52:34

标签: android matrix android-view

我正在尝试相对于另一个视图缩放一堆视图。所以,假设我有ImageView,其地图为ImageDrawable。 该地图上有一些POI(在位图中),我想在POI之上绘制我的视图,因为我希望它们可以被触摸。

我对如何实现这一点有一些想法:

1 - 我只是简单地拖动/缩放该图像并关于它的位置和比例我也可以使用MotionEvent getX和getY获得POI位置。 这是最丑陋但最快的解决方案。

2 - 使用GoogleMaps我的图片有地图图片叠加(我可以使用MapboxAndroid Ground Overlays来实现此目的。我会将地图移到“无处”位置,绘制我的自定义标记和完成的工作。 GoogleMaps会处理我的缩放,拖动,POI触摸等...

3 - 我正在使用的解决方案和我最喜欢的解决方案:拥有一个 ViewContainer 及其所有子视图,这些视图将遭受一些矩阵转换。

让我们看一些代码:

public class ZoomableContainer extends FrameLayout implements View.OnTouchListener {

    private static final float THRESHOLD = 50;
    private List<ImageView> mChildViews;
    private final GestureDetector mGestureDetector;

    private Matrix mMatrix = new Matrix();
    private Matrix mSavedMatrix = new Matrix();

    private static final int NONE = 0;
    private static final int DRAG = 1;
    private static final int ZOOM = 2;
    private int mMode = NONE;

    private PointF mStart = new PointF();
    private PointF mMid = new PointF();
    private float mOldDist = 1f;
    private float[] mLastEvent = null;

    public ZoomableContainer(ZoomInActivity context, List<ImageView> child) {
        super(context);
        mChildViews = new ArrayList<>(child);
        mGestureDetector = new GestureDetector(getContext(), new SingleTapConfirm());
        setClipChildren(false);
        setClipToPadding(false);

        for (ImageView view : mChildViews) {
            view.setScaleType(ImageView.ScaleType.MATRIX);
            addView(view);
        }
        setOnTouchListener(this);
    }

    public boolean onTouch(View v, MotionEvent event) {
        if (mGestureDetector.onTouchEvent(event)) {
            getViewInBounds(event);
        } else {
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_DOWN:
                    mSavedMatrix.set(mMatrix);
                    mStart.set(event.getX(), event.getY());
                    mMode = DRAG;
                    mLastEvent = null;
                    break;
                case MotionEvent.ACTION_POINTER_DOWN:
                    mOldDist = spacingBetweenTouch(event);
                    if (mOldDist > 10f) {
                        mSavedMatrix.set(mMatrix);
                        midPointBetweenTouch(mMid, event);
                        mMode = ZOOM;
                    }
                    mLastEvent = new float[4];
                    mLastEvent[0] = event.getX(0);
                    mLastEvent[1] = event.getX(1);
                    mLastEvent[2] = event.getY(0);
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_POINTER_UP:
                    mMode = NONE;
                    mLastEvent = null;
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (mMode == DRAG) {
                        mMatrix.set(mSavedMatrix);
                        float dx = event.getX() - mStart.x;
                        float dy = event.getY() - mStart.y;
                        mMatrix.postTranslate(dx, dy);
                    } else if (mMode == ZOOM) {
                        float newDist = spacingBetweenTouch(event);
                        if (newDist > 10f) {
                            mMatrix.set(mSavedMatrix);
                            float scale = (newDist / mOldDist);
                            mMatrix.postScale(scale, scale, mMid.x, mMid.y);
                        }
                    }
                    break;
            }

            if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_MOVE) {
                for (ImageView view : mChildViews) {
                    view.setImageMatrix(mMatrix);
                }
            }
        }
        return true;
    }

    private float spacingBetweenTouch(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return (float) Math.sqrt(x * x + y * y);
    }

    private void midPointBetweenTouch(PointF point, MotionEvent event) {
        float x = event.getX(0) + event.getX(1);
        float y = event.getY(0) + event.getY(1);
        point.set(x / 2, y / 2);
    }

    private void getViewInBounds(MotionEvent event) {
        // handle POI onClick() logic...
    }

    private class SingleTapConfirm extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onSingleTapUp(MotionEvent event) {
            return true;
        }
    }
}

因此,使用此View我可以 DRAG ZOOM ,这让人感到寒心。 List<ImageView> child包含我的所有POI和MAP(子[0])。现在它变得棘手:

  • 如果子视图位于(0,0),则比例效果很好,该视图可以相对于MAP视图正确缩放和平移。
  • 例如,如果某个孩子处于setX(100)setY(100),则该比例可以正常工作,但相对于de MAP视图,其位置不会改变。

我有一些问题:
1 - 为什么在应用矩阵变换后getX()getY()getScale() ...将不会更新? 2 - 我如何实现我想要的,postScale所有视图都会受到相对于MAP视图的比例(工作)和正确的翻译(不工作)(就像它们位于相同的原点时一样) scale = 1)

我已经尝试过{在if view.setImageMatrix(mMatrix);之后的onTouch内部)以使用视图新矩阵并参考Matrix.MTRANS_XMatrix.MSCALE_X in为了将视图转换回(在比例之后)到相对于地图的所需位置但没有运气。

我想我离解决方案的距离不远,或者我可能,但你能指出我吗? 谢谢你的帮助,希望我一直很清楚。

0 个答案:

没有答案