手勢 觸摸【縮放】GestureDetector MotionEvent 案例


GestureDetector和ScaleGestureDetector示例

/**
 * 演示【單點觸摸手勢識別器】
 * 演示【縮放手勢識別器】最簡單的使用
 * @author 白乾濤
 */
public class FirstActivity extends Activity implements OnTouchListener {
    private ImageView iv;
    private GestureDetector mGestureDetector;//單擊和雙擊事件手勢識別器
    private ScaleGestureDetector mScaleGestureDetector;//縮放事件手勢識別器
    private Matrix matrix = new Matrix();
    private DecimalFormat df = new DecimalFormat("0.00");//格式化float
    private float lastScale = 1;//記錄上次的縮放比例,下次縮放時是在此基礎上進行的
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        iv = new ImageView(this);
        iv.setImageResource(R.drawable.ic_launcher);
        iv.setScaleType(ScaleType.MATRIX);//用矩陣來繪制
        setContentView(iv);
        mGestureDetector = new GestureDetector(thisnew MyGestureListener());
        mScaleGestureDetector = new ScaleGestureDetector(thisnew SimpleOnScaleGestureListener() {
            @Override
            public boolean onScale(ScaleGestureDetector detector) {
                float scale = detector.getScaleFactor()//縮放因子,兩指靠攏時小於1
                float x = detector.getFocusX(), y = detector.getFocusY();//中心點坐標
                Log.i("bqt""縮放手勢  onScale," + df.format(scale) + "-" + df.format(x) + "-" + df.format(y));
                matrix.setScale(lastScale * scale, lastScale * scale);
                iv.setImageMatrix(matrix);
                return super.onScale(detector);
            }
            @Override
            public boolean onScaleBegin(ScaleGestureDetector detector) {
                Log.i("bqt""縮放手勢  onScaleBegin," + df.format(detector.getScaleFactor()));//始終是1
                return super.onScaleBegin(detector);
            }
            @Override
            public void onScaleEnd(ScaleGestureDetector detector) {
                super.onScaleEnd(detector);
                lastScale *= detector.getScaleFactor();
                Log.i("bqt""縮放手勢  onScaleEnd," + df.format(detector.getScaleFactor()));
            }
        });
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event);
        mScaleGestureDetector.onTouchEvent(event);
        return super.onTouchEvent(event);
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return false;//設置OnTouchListener時,返回值要為false,或者在onTouch()中將MotionEvent事件傳給GestureDetector,才能使手勢識別器生效
    }
    class MyGestureListener extends SimpleOnGestureListener {
        @Override
        //雙擊的【第二下】Touch down時觸發(只執行一次)
        public boolean onDoubleTap(MotionEvent e) {
            Log.i("bqt""onDoubleTap");
            return super.onDoubleTap(e);
        }
        @Override
        //雙擊的【第二下】Touch down和up都會觸發(執行次數不確定)。 
        public boolean onDoubleTapEvent(MotionEvent e) {
            Log.i("bqt""onDoubleTapEvent");
            return super.onDoubleTapEvent(e);
        }
        @Override
        //Touch down時觸發
        public boolean onDown(MotionEvent e) {
            Log.i("bqt""onDown");
            return super.onDown(e);
        }
        @Override
        //onScroll一點距離后,【拋擲時】觸發(若是輕輕的、慢慢的停止活動,而非拋擲,則很可能不觸發)
        //參數為手指接觸屏幕、離開屏幕一瞬間的動作事件,及手指水平、垂直方向移動的速度,像素/秒
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            Log.i("bqt""onFling");
            if ((e2.getRawX() - e1.getRawX()) > 100) {
                Log.i("bqt""onFling-從左到右滑");
                return true;//消耗事件
            }
            return super.onFling(e1, e2, velocityX, velocityY);
        }
        @Override
        //Touch了不移動一直Touch down時觸發 
        public void onLongPress(MotionEvent e) {
            Log.i("bqt""onLongPress");
            super.onLongPress(e);
        }
        @Override
        //Touch了滑動時觸發,e1代表觸摸時的事件,是不變的,e2代表滑動過程中的事件,是時刻變化的
        //distance是當前event2與上次回調時的event2之間的距離,代表上次回調之后到這次回調之前移動的距離
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            Log.i("bqt""onScroll-" + (int) e1.getX() + "-" + (int) e2.getX() + "-" + (int) distanceX + "-" + (int) distanceY);
            return super.onScroll(e1, e2, distanceX, distanceY);
        }
        @Override
        //Touch了還沒有滑動時觸發 
        public void onShowPress(MotionEvent e) {
            Log.i("bqt""onShowPress");
            super.onShowPress(e);
        }
        @Override
        //在touch down后又沒有滑動(onScroll),又沒有長按(onLongPress),然后Touchup時觸發。
        public boolean onSingleTapConfirmed(MotionEvent e) {
            Log.i("bqt""onSingleTapConfirmed");
            return super.onSingleTapConfirmed(e);
        }
        @Override
        //在touch down后又沒有滑動(onScroll),又沒有長按(onLongPress),然后Touchup時觸發。
        public boolean onSingleTapUp(MotionEvent e) {
            Log.i("bqt""onSingleTapUp");
            return super.onSingleTapUp(e);
        }
    }
}

MotionEvent示例:縮放圖片

public class SecondActivity extends Activity implements OnTouchListener {
    private ImageView iv;
    private float scale = 1;
    private float lastScale = 1;//記錄手指全部離開時的縮放比例,下次縮放時是在此基礎上進行的
    private float oldDist;//記錄第二個觸摸點和第一個觸摸點之間的距離 
    private Matrix mMatrix = new Matrix();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        iv = new ImageView(this);
        iv.setImageResource(R.drawable.ic_launcher);
        iv.setBackgroundColor(0x8822ffff);//從背景可以看出,此ImageView 是占用整個屏幕大小的
        iv.setScaleType(ScaleType.MATRIX);
        iv.setOnTouchListener(this);
        setContentView(iv);
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
            Log.i("bqt""ACTION_DOWN,第一個觸摸點,所以肯定為【1】" + event.getPointerCount());
            break;
        case MotionEvent.ACTION_UP://當屏幕上唯一的點被放開時觸發
            lastScale = scale;//記錄手指全部離開時的縮放比例,下次縮放時是在此基礎上進行的
            Log.i("bqt""ACTION_UP,最后一個觸摸點,之前觸摸點數肯定為【1】" + event.getPointerCount());
            break;
        case MotionEvent.ACTION_POINTER_UP://當屏幕上有多個點被按住,松開其中一個點時觸發
            Log.i("bqt""ACTION_POINTER_UP,少一個觸摸點,少之前的觸摸點數為" + event.getPointerCount());
            break;
        case MotionEvent.ACTION_POINTER_DOWN://當屏幕上已經有一個點被按住,此時再按下其他點時觸發
            if (event.getPointerCount() == 2) oldDist = spacing(event);//記錄第二個觸摸點和第一個觸摸點之間的距離 
            Log.i("bqt""ACTION_POINTER_DOWN,又一個觸摸點,目前觸摸點數為" + event.getPointerCount());
            break;
        case MotionEvent.ACTION_MOVE://當有點在屏幕上移動時觸發
            if (event.getPointerCount() == 2) {
                float newDist = spacing(event);//移動過程中,第二個點和第一個點的距離 
                if (Math.abs(newDist - oldDist) > 10) {//減小靈敏度
                    scale = lastScale * newDist / oldDist;
                    Log.i("bqt""ACTION_MOVE,縮放比例為" + scale);
                    mMatrix.setScale(scalescale);
                    iv.setImageMatrix(mMatrix);
                }
            }
            break;
        }
        return true;
    }
    /**
     * 返回兩個點之間的距離
     */
    private float spacing(MotionEvent event) {
        if (event.getPointerCount() >= 2) {
            float x = event.getX(0) - event.getX(1);
            float y = event.getY(0) - event.getY(1);
            return (float) Math.sqrt(x * x + y * y);
        } else return 0;
    }
}

MotionEvent示例:功能增強

public class ThirdActivity extends Activity implements OnTouchListener {
    private ImageView imageView;
    private Matrix startMatrix = new Matrix();//ImageView初始矩陣
    private Matrix matrix = new Matrix();//要給ImageView設置的矩陣
    private float startDis;//兩個手指的按下時的初始距離
    private PointF midPoint;//兩個手指的按下時中間點
    private PointF startPoint = new PointF();//第一個手指按下時的坐標位置
    private boolean isPointerUp;//當有手指放開時,如果不停止縮放,會導致圖片位置錯亂。后續可以優化
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        imageView = new ImageView(this);
        imageView.setImageResource(R.drawable.ic_launcher);
        imageView.setOnTouchListener(this);
        imageView.setScaleType(ScaleType.MATRIX);
        setContentView(imageView);
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
            Log.i("bqt""初始矩陣" + imageView.getImageMatrix());//值是會變的 {[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}
            startMatrix.set(imageView.getImageMatrix()); //獲取初始狀態
            startPoint.set(event.getX(), event.getY());//獲取開始時候的坐標位置
            isPointerUp = true;
            break;
        case MotionEvent.ACTION_MOVE:
            if (isPointerUp) {
                if (event.getPointerCount() == 1) { //移動圖片
                    float dx = event.getX() - startPoint.x// 得到X軸的移動距離
                    float dy = event.getY() - startPoint.y// 得到Y軸的移動距離
                    Log.i("bqt""移動距離" + (int) dx + "---" + (int) dy);
                    matrix.set(startMatrix);//先置為初始狀態
                    matrix.postTranslate(dx, dy);
                } else if (event.getPointerCount() == 2) { // 放大縮小圖片
                    float endDis = distance(event);// 距離
                    float scale = endDis / startDis;//ImageView縮放的比例
                    Log.i("bqt""縮放倍數" + scale);
                    matrix.set(startMatrix);
                    matrix.postScale(scale, scale, midPoint.xmidPoint.y);
                }
                imageView.setImageMatrix(matrix);
            }
            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            startDis = distance(event);
            midPoint = mid(event);
            startMatrix.set(imageView.getImageMatrix());//重置為目前的初始狀態
            break;
        case MotionEvent.ACTION_UP:
            break;
        case MotionEvent.ACTION_POINTER_UP:
            isPointerUp = false;
            break;
        }
        return true;
    }
    /** 計算兩個手指間的距離 */
    private float distance(MotionEvent event) {
        float dx = event.getX(1) - event.getX(0);
        float dy = event.getY(1) - event.getY(0);
        /** 使用勾股定理返回兩點之間的距離 */
        return (float) Math.sqrt(dx * dx + dy * dy);
    }
    /** 計算兩個手指間的中間點 */
    private PointF mid(MotionEvent event) {
        float midX = (event.getX(1) + event.getX(0)) / 2;
        float midY = (event.getY(1) + event.getY(0)) / 2;
        return new PointF(midX, midY);
    }
}

附件列表

     


    免責聲明!

    本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



     
    粵ICP備18138465號   © 2018-2025 CODEPRJ.COM