觸摸事件 Touch MotionEvent ACTION



MotionEvent簡介
      
      
      
              

當用戶觸摸屏幕時,將創建一個MontionEvent對象,MotionEvent包含了關於發生觸摸的位置、時間信息,以及觸摸事件的其他細節。

獲取MontionEvent對象的方法有:

  • 在View或Activity的onTouchEvent方法中: public boolean onTouchEvent(MotionEvent event) {}
  • 實現OnTouchListener接口后在onTouch方法中: public boolean onTouch(View v, MotionEvent event) {}

我們可以從一個MotionEvent對象中獲得哪些信息呢?
1、事件的類型
      可以通過getAction()獲得事件的類型,在android2.2之后加入了對多點觸控的支持,多點觸控時需使用getActionMasked()方法
      注意: event.getActionMasked()  event.getAction() & MotionEvent.ACTION_MASK  是等價的
      getActionMasked的低8位是動作類型信息(和getAction的值是一樣的), 8-15位是觸控點的索引信息( 即表示是哪一個觸控點的事件)
      具體看這里: http://my.oschina.net/banxi/blog/56421  
  • ACTION_DOWN: 表示用戶開始觸摸(在第一個點被按下時觸發)
  • ACTION_MOVE: 當有點在屏幕上移動時觸發,注意的是,由於靈敏度很高,所以基本上只要有點在屏幕上,此事件就會不停地被觸發
  • ACTION_UP:表示用戶抬起了手指(當屏幕上唯一的點被放開時觸發)
  • ACTION_CANCEL:表示手勢被取消了
  • ACTION_OUTSIDE: 表示用戶觸碰超出了正常的UI邊界
  • ACTION_POINTER_DOWN:當屏幕上已經有一個點被按住,此時再按下其他點時觸發
  • ACTION_POINTER_UP:當屏幕上有多個點被按住,松開其中一個點時觸發(非最后一個點)
2、事件發生的位置
  • getX() 獲得事件發生時,觸摸的中間區域相對view的觸摸位置坐標(不會超過view的長度和寬度)
  • getRawX() 和上面getX()不同的是,此方法獲得的是相對屏幕的位置坐標
  • getX(int pointerIndex)  在多點觸控中,用來獲取第pointerIndex個觸控點的x位置坐標
3、其他信息
  • getPointerCount(); //獲取觸控點的數量,比如2則可能是兩個手指同時按壓屏幕
  • getPointerId(nID); //對於每個觸控的點的細節,我們可以通過一個循環執行getPointerId方法獲取索引
  • getPressure(nID); //LCD可以感應出用戶的手指壓力,當然具體的級別由驅動和物理硬件決定的
  • getDownTime() //按下開始時間
  • getEventTime() // 事件結束時間
  • getEventTime()-event.getDownTime()); //總共按下時花費時間
  • getEdgeFlags():當事件類型是ActionDown時可以通過此方法獲得手指觸控開始的邊界,如果是的話,有如下幾種值:EDGE_LEFT、EDGE_TOP、EDGE_RIGHT、EDGE_BOTTOM

定義的常量
      
      
      
              

MotionEvent中定義的常量有以下幾個

touch事件:

  • ACTION_DOWN = 0;單點觸摸動作
  • ACTION_UP = 1;單點觸摸離開動作
  • ACTION_MOVE = 2;觸摸點移動動作
  • ACTION_CANCEL = 3;觸摸動作取消
  • ACTION_OUTSIDE = 4;觸摸動作超出邊界
  • ACTION_POINTER_DOWN = 5;多點觸摸動作
  • ACTION_POINTER_UP = 6;多點離開動作
其他:
  • ACTION_HOVER_MOVE = 7;
  • ACTION_SCROLL = 8;
  • ACTION_HOVER_ENTER = 9;
  • ACTION_HOVER_EXIT = 10;
  • ACTION_MASK = 0X000000ff 掩碼常量
  • ACTION_POINTER_INDEX_MASK = 0X0000ff00 動作掩碼
  • ACTION_POINTER_INDEX_SHIFT = 8 觸摸點索引掩碼,獲取觸摸點索引需要移動的位數


雙指縮放圖片
      
      
      
              

public class MainActivity extends Activity implements OnTouchListener {

    private ImageView myImageView;
    private int mode = 0; //觸摸點數
    private float oldDist;
    private float scale = 1;
    private float lastScale = 1;//記錄手指全部離開時的縮放比例,下次縮放時是在次基礎上進行的
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        myImageView = new ImageView(this);
        myImageView.setImageResource(R.drawable.ic_launcher);
        myImageView.setBackgroundColor(0x8822ffff); //從背景可以看出,此ImageView 是占用整個屏幕大小的
        myImageView.setScaleType(ScaleType.MATRIX);
        myImageView.setOnTouchListener(this);
        setContentView(myImageView);
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            mode = 1;
            Log.e("View""ACTION_DOWN,觸摸點數為1");
            break;
        case MotionEvent.ACTION_UP://當屏幕上唯一的點被放開時觸發
            lastScale = scale;
            mode = 0;
            Log.e("View""ACTION_UP,觸摸點數為0");
            break;
        case MotionEvent.ACTION_POINTER_UP://當屏幕上有多個點被按住,松開其中一個點時觸發(即非最后一個點被放開時)
            mode -= 1;
            Log.e("View""ACTION_POINTER_UP,觸摸點數-1");
            break;
        case MotionEvent.ACTION_POINTER_DOWN://當屏幕上已經有一個點被按住,此時再按下其他點時觸發
            oldDist = spacing(event);//第二個點按下時的和第一個點的距離 
            mode += 1;
            Log.e("View""ACTION_POINTER_DOWN,觸摸點數+1," + oldDist);
            break;
        case MotionEvent.ACTION_MOVE://當有點在屏幕上移動時觸發
            if (mode >= 2) {
                float newDist = spacing(event);//移動過程中,第二個點和第一個點的距離 
                if (Math.abs(newDist - oldDist) > 10) {//減小靈敏度
                    scale = lastScale * newDist / oldDist;
                    Log.e("View""ACTION_MOVE,縮放比例為" + scale);
                    Matrix mMatrix = new Matrix();
                    mMatrix.setScale(scalescale);
                    myImageView.setImageMatrix(mMatrix);
                }
                break;
            }
        }
        return true;//若view的onTouch返回true(只有這樣才能接收事件),那么onTouchEvent就收不到事件了(包括down事件)
    }
    /**
     * 返回兩個點之間的距離,注意,如果只有一個觸摸點的話調用getX(1)就掛掉了,為減少冗余的判斷,我們可以放在try中
     */
    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);
    }
}

縮放、移動圖片
      
      
      
              

public class MainActivity extends Activity {

    private ImageView imageView;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        imageView = (ImageView) this.findViewById(R.id.imageView);
        imageView.setOnTouchListener(new TouchListener());
    }
    private final class TouchListener implements OnTouchListener {
        /** 記錄是拖拉照片模式還是放大縮小照片模式 */
        private int mode = 0;// 初始狀態  
        /** 拖拉照片模式 */
        private static final int MODE_DRAG = 1;
        /** 放大縮小照片模式 */
        private static final int MODE_ZOOM = 2;
        /** 用於記錄開始時候的坐標位置 */
        private PointF startPoint = new PointF();
        /** 用於記錄拖拉圖片移動的坐標位置 */
        private Matrix matrix = new Matrix();
        /** 用於記錄圖片要進行拖拉時候的坐標位置 */
        private Matrix currentMatrix = new Matrix();
        /** 兩個手指的開始距離 */
        private float startDis;
        /** 兩個手指的中間點 */
        private PointF midPoint;
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            /** 通過與運算保留最后八位 MotionEvent.ACTION_MASK = 255 */
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
            // 手指壓下屏幕
            case MotionEvent.ACTION_DOWN:
                mode = MODE_DRAG;
                // 記錄ImageView當前的移動位置
                currentMatrix.set(imageView.getImageMatrix());
                startPoint.set(event.getX(), event.getY());
                break;
            // 手指在屏幕上移動,該事件會被不斷觸發
            case MotionEvent.ACTION_MOVE:
                // 拖拉圖片
                if (mode == MODE_DRAG) {
                    float dx = event.getX() - startPoint.x// 得到x軸的移動距離
                    float dy = event.getY() - startPoint.y// 得到x軸的移動距離
                    // 在沒有移動之前的位置上進行移動
                    matrix.set(currentMatrix);
                    matrix.postTranslate(dx, dy);
                }
                // 放大縮小圖片
                else if (mode == MODE_ZOOM) {
                    float endDis = distance(event);// 結束距離
                    if (endDis > 10f) { // 兩個手指並攏在一起的時候像素大於10
                        float scale = endDis / startDis;// 得到縮放倍數
                        matrix.set(currentMatrix);
                        matrix.postScale(scale, scale, midPoint.xmidPoint.y);
                    }
                }
                break;
            // 手指離開屏幕
            case MotionEvent.ACTION_UP:
                // 當觸點離開屏幕,但是屏幕上還有觸點(手指)
            case MotionEvent.ACTION_POINTER_UP:
                mode = 0;
                break;
            // 當屏幕上已經有觸點(手指),再有一個觸點壓下屏幕
            case MotionEvent.ACTION_POINTER_DOWN:
                mode = MODE_ZOOM;
                /** 計算兩個手指間的距離 */
                startDis = distance(event);
                /** 計算兩個手指間的中間點 */
                if (startDis > 10f) { // 兩個手指並攏在一起的時候像素大於10
                    midPoint = mid(event);
                    //記錄當前ImageView的縮放倍數
                    currentMatrix.set(imageView.getImageMatrix());
                }
                break;
            }
            imageView.setImageMatrix(matrix);
            return true;
        }
        /** 計算兩個手指間的距離 */
        private float distance(MotionEvent event) {
            float dx = event.getX(1) - event.getX(0);
            float dy = event.getY(1) - event.getY(0);
            /** 使用勾股定理返回兩點之間的距離 */
            return FloatMath.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