zoukankan      html  css  js  c++  java
  • 自定义View(三)实现简单的可拖动、可缩放的ImageView

       实现技术主要用到1、多点触摸  2、matrix的矩阵,平移、缩放

    根据手指的数量判断是进行的拖动、还是缩放动作

    package com.bi.xintest;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Matrix;
    import android.graphics.PointF;
    import android.util.AttributeSet;
    import android.util.DisplayMetrics;
    import android.util.FloatMath;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.widget.ImageView;
    
    public class ScaleView extends ImageView {
    
        final public static int DRAG = 1;
        final public static int ZOOM = 2;
    
        public int mode = 0;
    
        private Matrix matrix = new Matrix();
        private Matrix matrix1 = new Matrix();
        private Matrix saveMatrix = new Matrix();
    
        private float x_down = 0;
        private float y_down = 0;
    
        private Bitmap touchImg = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
    
        private PointF mid = new PointF();
    
    
        private float initDis = 1f;
    
        private int screenWidth, screenHeight;
    
        private float[] x = new float[4];
        private float[] y = new float[4];
    
        private boolean flag = false;
    
        public ScaleView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        public ScaleView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public ScaleView(Context context) {
            super(context);
            touchImg = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
            DisplayMetrics dm = getResources().getDisplayMetrics();
            screenWidth = dm.widthPixels;
            screenHeight = dm.heightPixels;
            matrix = new Matrix();
            // this.setScaleType(ScaleType.MATRIX);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
    
            canvas.save();
            // 根据 matrix 来重绘新的view
            canvas.drawBitmap(touchImg, matrix, null);
            canvas.restore();
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
    
            int action = event.getAction();
            // 多点触摸的时候 必须加上MotionEvent.ACTION_MASK
            switch (action & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_DOWN:
                    saveMatrix.set(matrix);
                    x_down = event.getX();
                    y_down = event.getY();
                    // 初始为drag模式
                    mode = DRAG;
                    break;
    
                case MotionEvent.ACTION_POINTER_DOWN:
                    saveMatrix.set(matrix);
                    // 初始的两个触摸点间的距离
                    initDis = spacing(event);
                    // 设置为缩放模式
                    mode = ZOOM;
                    // 多点触摸的时候 计算出中间点的坐标
                    midPoint(mid, event);
                    break;
    
                case MotionEvent.ACTION_MOVE:
    
                    // drag模式
                    if (mode == DRAG) {
                        // 设置当前的 matrix
                        matrix1.set(saveMatrix);
                        // 平移 当前坐标减去初始坐标 移动的距离
                        matrix1.postTranslate(event.getX() - x_down, event.getY()
                                - y_down);// 平移
                        // 判断达到移动标准
                        flag = checkMatrix(matrix1);
                        if (flag) {
                            // 设置matrix
                            matrix.set(matrix1);
    
                            // 调用ondraw重绘
                            invalidate();
                        }
                    } else if (mode == ZOOM) {
                        matrix1.set(saveMatrix);
                        float newDis = spacing(event);
                        // 计算出缩放比例
                        float scale = newDis / initDis;
    
                        // 以mid为中心进行缩放
                        matrix1.postScale(scale, scale, mid.x, mid.y);
                        flag = checkMatrix(matrix1);
                        if (flag) {
                            matrix.set(matrix1);
                            invalidate();
                        }
                    }
                    break;
    
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_POINTER_UP:
                    mode = 0;
                    break;
            }
    
            return true;
    
        }
    
        //取两点的距离
        private float spacing(MotionEvent event) {
            try {
                float x = event.getX(0) - event.getX(1);
                float y = event.getY(0) - event.getY(1);
                return (float)Math.sqrt(x * x + y * y);
            } catch (IllegalArgumentException ex) {
                Log.v("TAG", ex.getLocalizedMessage());
                return 0;
            }
        }
    
        //取两点的中点
        private void midPoint(PointF point, MotionEvent event) {
            try {
                float x = event.getX(0) + event.getX(1);
                float y = event.getY(0) + event.getY(1);
                point.set(x / 2, y / 2);
            } catch (IllegalArgumentException ex) {
    
                //这个异常是android自带的,网上清一色的这么说。。。。
                Log.v("TAG", ex.getLocalizedMessage());
            }
        }
    
        private boolean checkMatrix(Matrix m) {
    
            GetFour(m);
    
            // 出界判断
            //view的右边缘x坐标小于屏幕宽度的1/3的时候,
            // view左边缘大于屏幕款短的2/3的时候
            //view的下边缘在屏幕1/3上的时候
            //view的上边缘在屏幕2/3下的时候
            if ((x[0] < screenWidth / 3 && x[1] < screenWidth / 3
                    && x[2] < screenWidth / 3 && x[3] < screenWidth / 3)
                    || (x[0] > screenWidth * 2 / 3 && x[1] > screenWidth * 2 / 3
                    && x[2] > screenWidth * 2 / 3 && x[3] > screenWidth * 2 / 3)
                    || (y[0] < screenHeight / 3 && y[1] < screenHeight / 3
                    && y[2] < screenHeight / 3 && y[3] < screenHeight / 3)
                    || (y[0] > screenHeight * 2 / 3 && y[1] > screenHeight * 2 / 3
                    && y[2] > screenHeight * 2 / 3 && y[3] > screenHeight * 2 / 3)) {
                return true;
            }
            // 图片现宽度
            double width = Math.sqrt((x[0] - x[1]) * (x[0] - x[1]) + (y[0] - y[1])
                    * (y[0] - y[1]));
            // 缩放比率判断 宽度打雨3倍屏宽,或者小于1/3屏宽
            if (width < screenWidth / 3 || width > screenWidth * 3) {
                return true;
            }
            return false;
    
            // if ((x[0] >= 0 && x[1] >= 0 && x[2] >= 0 && x[3] >= 0)
            // && (x[0] <= screenWidth && x[1] <= screenWidth
            // && x[2] <= screenWidth && x[3] <= screenWidth)
            // && (y[0] >= 0 && y[1] >= 0 && y[2] >= 0 && y[3] >= 0) && (y[0] <=
            // screenHeight
            // && y[1] <= screenHeight && y[2] <= screenHeight && y[3] <=
            // screenHeight)) {
            //
            // return true;
            // }
            //
            // return false;
        }
    
        private void GetFour(Matrix matrix) {
            float[] f = new float[9];
            matrix.getValues(f);
    //        StringBuffer sb = new StringBuffer();
    //        for(float ff : f)
    //        {
    //            sb.append(ff+"  ");
    //        }
            // 图片4个顶点的坐标
            //矩阵  9     MSCALE_X 缩放的, MSKEW_X 倾斜的    。MTRANS_X 平移的
            x[0] = f[Matrix.MSCALE_X] * 0 + f[Matrix.MSKEW_X] * 0
                    + f[Matrix.MTRANS_X];
            y[0] = f[Matrix.MSKEW_Y] * 0 + f[Matrix.MSCALE_Y] * 0
                    + f[Matrix.MTRANS_Y];
            x[1] = f[Matrix.MSCALE_X] * touchImg.getWidth() + f[Matrix.MSKEW_X] * 0
                    + f[Matrix.MTRANS_X];
            y[1] = f[Matrix.MSKEW_Y] * touchImg.getWidth() + f[Matrix.MSCALE_Y] * 0
                    + f[Matrix.MTRANS_Y];
            x[2] = f[Matrix.MSCALE_X] * 0 + f[Matrix.MSKEW_X]
                    * touchImg.getHeight() + f[Matrix.MTRANS_X];
            y[2] = f[Matrix.MSKEW_Y] * 0 + f[Matrix.MSCALE_Y]
                    * touchImg.getHeight() + f[Matrix.MTRANS_Y];
            x[3] = f[Matrix.MSCALE_X] * touchImg.getWidth() + f[Matrix.MSKEW_X]
                    * touchImg.getHeight() + f[Matrix.MTRANS_X];
            y[3] = f[Matrix.MSKEW_Y] * touchImg.getWidth() + f[Matrix.MSCALE_Y]
                    * touchImg.getHeight() + f[Matrix.MTRANS_Y];
        }
    
    }
  • 相关阅读:
    彻底理解ThreadLocal(转)
    javascript中神奇的(+)加操作符
    quartz集群调度机制调研及源码分析---转载
    quartz源码解析--转
    通过Spring @PostConstruct 和 @PreDestroy 方法 实现初始化和销毁bean之前进行的操作
    LeetCode 917. Reverse Only Letters (仅仅反转字母)
    LeetCode 893. Groups of Special-Equivalent Strings (特殊等价字符串组)
    LeetCode 824. Goat Latin (山羊拉丁文)
    LeetCode 443. String Compression (压缩字符串)
    LeetCode 387. First Unique Character in a String (字符串中的第一个唯一字符)
  • 原文地址:https://www.cnblogs.com/bimingcong/p/5807407.html
Copyright © 2011-2022 走看看