onTouch事件
做什么都好先了解原理以后的工作就会更简单,关于手势以及我们熟悉的onclick,
onLongClick事件都是基于对onTouch事件的捕捉和处理。那么在使用手势工具类的前提下我们应该去学习了解基本的onTouch事件。

onTouch常用的以下4个事件:

1、ACTION_DOWN:
表示按下了屏幕,第一个执行也是必然执行的方法。

2、ACTION_MOVE:
表示为移动手势,会不断的执行直到触摸停止。

3、ACTION_UP :
表示为离开屏幕,触摸停止的时候执行。

4、ACTION_CANCEL:
表示取消手势,不会由用户产生,而是由程序产生的。
一个Action_DOWN, 多个ACTION_MOVE, 1个ACTION_UP,就构成了Android中众多的事件。

onTouch的参数
View
受到Touch事件的view对象

MotionEvent
包含的事件的详细信息,例如触摸点的信息,触摸事件类型的信息等
MotionEvent的方法例如getRowX所描述的都是触摸点的信息。

几个重要方法的说明:

getRowX:触摸点相对于屏幕的X坐标
getRowY:触摸点相对于屏幕的Y坐标
getX: 触摸点相对于view的X坐标 :即对其进行touch监听的那个view
getY: 触摸点相对于view的X坐标
getTop: 按钮左上角相对于父view(LinerLayout)的y坐标
getLeft: 按钮左上角相对于父view(LinerLayout)的x坐标

onTouch的返回值
作用:
这里的返回值代表的是,对于这个触摸事件touch是否已经处理完成。
如果我们设置返回值为true代表的是处理完成,这样就不会再传递给下一个对象。也就是说后面的控件或者对象就不会接收到触摸事件了。
反之,后面的对象或控件会在此接收到这个触摸事件并被调用。

实践
在学习基础知识之后,我们来看看如何使用这些来实现一个可以拖动的view吧。

public class MoveTouch implements View.OnTouchListener {


    private int[] temp = new int[2];

    private int dx, dy;

    private boolean isMove = false;

    private Context context;


    public MoveTouch(Context context) {

        this.context = context;

    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {


        int x = (int) event.getRawX();

        int y = (int) event.getRawY();

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:


                dx = (int) event.getRawX();

                dy = (int) event.getRawY();

                temp[0] = x - v.getLeft();

                temp[1] = y - v.getTop();


//              temp[0]=(int)event.getX();  //获取触摸点view 距离该view左边的距离 等同于 x-v.getLeft() 为了 保证坐标的正确性建议使用上面的方法

//              temp[1]=(int)event.getY(); //按 y - temp[1] 这样得到的不是该view距离父view的距离,而是距离屏幕顶部的距离 包括状态栏等

                isMove = false;


                break;

            case MotionEvent.ACTION_MOVE:

                /**
                 * 对view的按下的操作进行判断是否是移动操作
                 */
                if (Math.abs(dx - x) > 10 || Math.abs(dy - y) > 10) {

                    isMove = true;

                }


                if (isMove) {


                    v.layout(x - temp[0], y - temp[1], x + v.getWidth() - temp[0], y + v.getHeight() - temp[1]);


                }

                break;


            case MotionEvent.ACTION_UP:


                if (!isMove) {


                    Toast.makeText(context, "被点击了", Toast.LENGTH_SHORT).show();


                }


                break;


        }


        return true;//表示我自己处理这个触摸事件,不往下传递
    }


}

接下来再看看触摸事件和手势
手势操作
关于手势操作,这里其实说的是Android提供的工具类,通过GestureDetector 类来识别和处理onTouch事件,简化使用。

一般用到下面的三个类。

android.view.GestureDetector
手势操作的识别类,通过他来使用下面的识别接口。

android.view.GestureDetector.SimpleOnGestureListener
手势识别的接口类,使用他可以按需重载自己想要的方法,方法多

android.view.GestureDetector.OnGestureListener;
手势识别的类,SimpleOnGestureListener接口的父类。使用他需要实现他所有的方法。

方法说明:
OnGestureListener有下面的几个方法:

按下(onDown):
在按下时调用。

抛掷(onFling):
手指在触摸屏上迅速移动,并松开的动作。

长按(onLongPress):
手指按在持续一段时间,并且没有松开。

滚动(onScroll):
手指在触摸屏上滑动。

按住(onShowPress):
手指按在触摸屏上,它的时间范围在按下起效,在长按之前。

抬起(onSingleTapUp):
手指离开触摸屏的那一刹那。

SimpleOnGestureListener比OnGestureListener多出来的方法:

双击(onDoubleTap)
双击的第二下Touch down时触发

双击事件(onDoubleTapEvent)
双击的第二下Touch down和up都会触发一次,可用e.getAction()区分。

实践
其实看到上面的介绍应该可以看出来,其实手势就是对我们的触摸事件的一些操作进行了封装,变得更简单,简洁,方便我们的使用

public class MyGesture implements View.OnTouchListener, GestureDetector.OnGestureListener {

    private Context context;

    private GestureDetector gestureDetector;

    private int[] temp = new int[2];

    private View v;

    public MyGesture(Context context) {

        this.context = context;
        gestureDetector = new GestureDetector(context, this);

    }

    @Override
    public boolean onDown(MotionEvent e) {

        temp[0]=(int)e.getRawX()-v.getLeft();
        temp[1]=(int)e.getRawY()-v.getTop();


        return false;
    }

    /**
     *  用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发

     // 注意和onDown()的区别,强调的是没有松开或者拖动的状态
     * @param e
     */
    @Override
    public void onShowPress(MotionEvent e) {

    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {

        Toast.makeText(context, "被点击了", Toast.LENGTH_SHORT).show();

        return false;
    }

    /**
     * 按住然后滑动  e1 手开始触碰屏幕的位置的MotionEvent对象
     * @param e1
     * @param e2  手结束触碰屏幕的位置的MotionEvent对象
     * @param distanceX
     * @param distanceY
     * @return
     */
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {


        int x=(int)e2.getRawX();

        int y=(int)e2.getRawY();


        v.layout(x-temp[0],y-temp[1],x+v.getWidth()-temp[0],y-temp[1]+v.getHeight());


        return false;
    }

    @Override
    public void onLongPress(MotionEvent e) {

    }

    /**
     * 快速滑动并且移开
     * @param e1
     * @param e2
     * @param velocityX
     * @param velocityY
     * @return
     */
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        return false;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {

        this.v=v;

        gestureDetector.onTouchEvent(event);

        return true;
    }
}

如果使用GestureDetector.SimpleOnGestureListener代码更简洁这里我们就不是实现了,而是继承GestureDetector.SimpleOnGestureListener这个类

public class MySimpleGesture extends GestureDetector.SimpleOnGestureListener implements View.OnTouchListener{


    @Override
    public boolean onTouch(View v, MotionEvent event) {


        return false;
    }

    @Override
    public boolean onDown(MotionEvent e) {
        return super.onDown(e);
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return super.onScroll(e1, e2, distanceX, distanceY);
    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return super.onSingleTapUp(e);
    }



}

实现我就不写了,有兴趣的童鞋可以做一下,练练手。~