Android ImageView Scaling and translating issue

后端 未结 3 589
一向
一向 2020-11-21 23:35

I’m developing an android application (API 19 4.4) and I encounter some issue with ImageViews. I have a SurfaceView, in which I dynamically add ImageViews which I want to re

相关标签:
3条回答
  • 2020-11-22 00:07

    I finally use this (spacing is used to calculated the distance between two fingers), I offset the imageview after scaling to keep it centered, works fine for now :

        float newDist = spacing(event);
                float scale = newDist / oldDist;
    
                int oldH =getLayoutParams().height;
                int oldW =getLayoutParams().width;
    
                int newH =(int) (getLayoutParams().height*scale);
                int newW =(int) (getLayoutParams().width*scale);
    
                if(newH<MAX_SIZE && newW<MAX_SIZE){
                    //scale the height and width of the view
                    getLayoutParams().height = newH;
                    getLayoutParams().width = newW;
    
                    //calculate the X and Y offset to apply after scaling to keep the image centered
                    int xOffset = (int)(getLayoutParams().height - oldH)/2;
                    int yOffset = (int)(getLayoutParams().width - oldW)/2;
    
                    setX(getX()-xOffset);
                    setY(getY()-yOffset);
                    requestLayout();
                    setAdjustViewBounds(true);
    
                    oldDist=newDist; 
    
    0 讨论(0)
  • 2020-11-22 00:25

    this is a working example of two fingers move/scale/rotate (note: the code is quite short due to smart detector used - see MatrixGestureDetector):

    class ViewPort extends View {
        List<Layer> layers = new LinkedList<Layer>();
        int[] ids = {R.drawable.layer0, R.drawable.layer1, R.drawable.layer2};
    
        public ViewPort(Context context) {
            super(context);
            Resources res = getResources();
            for (int i = 0; i < ids.length; i++) {
                Layer l = new Layer(context, this, BitmapFactory.decodeResource(res, ids[i]));
                layers.add(l);
            }
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            for (Layer l : layers) {
                l.draw(canvas);
            }
        }
    
        private Layer target;
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                target = null;
                for (int i = layers.size() - 1; i >= 0; i--) {
                    Layer l = layers.get(i);
                    if (l.contains(event)) {
                        target = l;
                        layers.remove(l);
                        layers.add(l);
                        invalidate();
                        break;
                    }
                }
            }
            if (target == null) {
                return false;
            }
            return target.onTouchEvent(event);
        }
    }
    
    class Layer implements MatrixGestureDetector.OnMatrixChangeListener {
        Matrix matrix = new Matrix();
        Matrix inverse = new Matrix();
        RectF bounds;
        View parent;
        Bitmap bitmap;
        MatrixGestureDetector mgd = new MatrixGestureDetector(matrix, this);
    
        public Layer(Context ctx, View p, Bitmap b) {
            parent = p;
            bitmap = b;
            bounds = new RectF(0, 0, b.getWidth(), b.getHeight());
            matrix.postTranslate(50 + (float) Math.random() * 50, 50 + (float) Math.random() * 50);
        }
    
        public boolean contains(MotionEvent event) {
            matrix.invert(inverse);
            float[] pts = {event.getX(), event.getY()};
            inverse.mapPoints(pts);
            if (!bounds.contains(pts[0], pts[1])) {
                return false;
            }
            return Color.alpha(bitmap.getPixel((int) pts[0], (int) pts[1])) != 0;
        }
    
        public boolean onTouchEvent(MotionEvent event) {
            mgd.onTouchEvent(event);
            return true;
        }
    
        @Override
        public void onChange(Matrix matrix) {
            parent.invalidate();
        }
    
        public void draw(Canvas canvas) {
            canvas.drawBitmap(bitmap, matrix, null);
        }
    }
    
    class MatrixGestureDetector {
        private static final String TAG = "MatrixGestureDetector";
    
        private int ptpIdx = 0;
        private Matrix mTempMatrix = new Matrix();
        private Matrix mMatrix;
        private OnMatrixChangeListener mListener;
        private float[] mSrc = new float[4];
        private float[] mDst = new float[4];
        private int mCount;
    
        interface OnMatrixChangeListener {
            void onChange(Matrix matrix);
        }
    
        public MatrixGestureDetector(Matrix matrix, MatrixGestureDetector.OnMatrixChangeListener listener) {
            this.mMatrix = matrix;
            this.mListener = listener;
        }
    
        public void onTouchEvent(MotionEvent event) {
            if (event.getPointerCount() > 2) {
                return;
            }
    
            int action = event.getActionMasked();
            int index = event.getActionIndex();
    
            switch (action) {
                case MotionEvent.ACTION_DOWN:
                case MotionEvent.ACTION_POINTER_DOWN:
                    int idx = index * 2;
                    mSrc[idx] = event.getX(index);
                    mSrc[idx + 1] = event.getY(index);
                    mCount++;
                    ptpIdx = 0;
                    break;
    
                case MotionEvent.ACTION_MOVE:
                    for (int i = 0; i < mCount; i++) {
                        idx = ptpIdx + i * 2;
                        mDst[idx] = event.getX(i);
                        mDst[idx + 1] = event.getY(i);
                    }
                    mTempMatrix.setPolyToPoly(mSrc, ptpIdx, mDst, ptpIdx, mCount);
                    mMatrix.postConcat(mTempMatrix);
                    if(mListener != null) {
                        mListener.onChange(mMatrix);
                    }
                    System.arraycopy(mDst, 0, mSrc, 0, mDst.length);
                    break;
    
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_POINTER_UP:
                    if (event.getPointerId(index) == 0) ptpIdx = 2;
                    mCount--;
                    break;
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 00:28

    I tried to implementation of multiple touch on view not on bitmap using matrix, now i success. Now i think it will helpful to you for individual gesture for multiple image. Try it, it work best for me.

    public class MultiTouchImageView extends ImageView implements OnTouchListener{
    
    float[] lastEvent = null;
    float d = 0f;
    float newRot = 0f;
    public static String fileNAME;
    public static int framePos = 0;
    //private ImageView view;
    private boolean isZoomAndRotate;
    private boolean isOutSide;
    // We can be in one of these 3 states
    private static final int NONE = 0;
    private static final int DRAG = 1;
    private static final int ZOOM = 2;
    private int mode = NONE;
    
    private PointF start = new PointF();
    private PointF mid = new PointF();
    float oldDist = 1f;
    public MultiTouchImageView(Context context) {
        super(context);
    }
    
    
    public MultiTouchImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    
    
    public MultiTouchImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    
    @SuppressWarnings("deprecation")
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        //view = (ImageView) v;
        bringToFront();
        // Handle touch events here...
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            //savedMatrix.set(matrix);
            start.set(event.getX(), event.getY());
            mode = DRAG;
            lastEvent = null;
            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            oldDist = spacing(event);
            if (oldDist > 10f) {
                midPoint(mid, event);
                mode = ZOOM;
            }
    
            lastEvent = new float[4];
            lastEvent[0] = event.getX(0);
            lastEvent[1] = event.getX(1);
            lastEvent[2] = event.getY(0);
            lastEvent[3] = event.getY(1);
            d =  rotation(event);
            break;
        case MotionEvent.ACTION_UP:
            isZoomAndRotate = false;
        case MotionEvent.ACTION_OUTSIDE:
            isOutSide = true;
            mode = NONE;
            lastEvent = null;
        case MotionEvent.ACTION_POINTER_UP:
            mode = NONE;
            lastEvent = null;
            break;
        case MotionEvent.ACTION_MOVE:
            if(!isOutSide){
                if (mode == DRAG && !isZoomAndRotate) {
                    isZoomAndRotate = false;
                    setTranslationX((event.getX() - start.x) + getTranslationX());
                    setTranslationY((event.getY() - start.y) + getTranslationY());
                } else if (mode == ZOOM && event.getPointerCount() == 2) {
                    isZoomAndRotate = true;
                    boolean isZoom = false;
                    if(!isRotate(event)){
                        float newDist = spacing(event);
                        if (newDist > 10f) {
                            float scale = newDist / oldDist * getScaleX();
                            setScaleX(scale);
                            setScaleY(scale);
                            isZoom = true;
                        }
                    }
                    else if(!isZoom){
                        newRot = rotation(event);
                        setRotation((float)(getRotation() + (newRot - d)));
                    }
                }
            }
    
            break;
        }
        new GestureDetector(new MyGestureDectore());
        Constants.currentSticker = this;
        return true;
    }
    private class MyGestureDectore extends GestureDetector.SimpleOnGestureListener{
    
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            bringToFront();
            return false;
        }
    
        @Override
        public boolean onDoubleTapEvent(MotionEvent e) {
            return false;
        }
    
    }
    private float rotation(MotionEvent event) {
        double delta_x = (event.getX(0) - event.getX(1));
        double delta_y = (event.getY(0) - event.getY(1));
        double radians = Math.atan2(delta_y, delta_x);
        return (float) Math.toDegrees(radians);
    }
    private float spacing(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return FloatMath.sqrt(x * x + y * y);
    }
    
    private void midPoint(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 boolean isRotate(MotionEvent event){
        int dx1 = (int) (event.getX(0) - lastEvent[0]);
        int dy1 = (int) (event.getY(0) - lastEvent[2]);
        int dx2 = (int) (event.getX(1) - lastEvent[1]);
        int dy2 = (int) (event.getY(1) - lastEvent[3]);
        Log.d("dx1 ", ""+ dx1);
        Log.d("dx2 ", "" + dx2);
        Log.d("dy1 ", "" + dy1);
        Log.d("dy2 ", "" + dy2);
        //pointer 1
        if(Math.abs(dx1) > Math.abs(dy1) && Math.abs(dx2) > Math.abs(dy2)) {
            if(dx1 >= 2.0 && dx2 <=  -2.0){
                Log.d("first pointer ", "right");
                return true;
            }
            else if(dx1 <= -2.0 && dx2 >= 2.0){
                Log.d("first pointer ", "left");
                return true;
            }
        }
        else {
             if(dy1 >= 2.0 && dy2 <=  -2.0){
                    Log.d("seccond pointer ", "top");
                    return true;
                }
                else if(dy1 <= -2.0 && dy2 >= 2.0){
                    Log.d("second pointer ", "bottom");
                    return true; 
                }
    
        }
    
        return false;
    }
    }
    
    0 讨论(0)
提交回复
热议问题