View中消息传递:onTouch() +onInterceptTouchEvent() + GestureDetector 学习

本文介绍了Android中View的触摸事件处理,包括OnTouchListener、onTouchEvent()和onInterceptTouchEvent()的使用,以及GestureDetector的基础知识,包括各种手势的触发条件和顺序。通过对实验的分析,展示了如何拦截和处理触摸事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考:http://blog.youkuaiyun.com/harvic880925/article/details/39520901
http://blog.youkuaiyun.com/lvxiangan/article/details/9309927

一、概述:

View类有个View.OnTouchListener内部接口,通过重写他的onTouch(View v, MotionEvent event)方法,我们可以处理一些touch事件,但无法完成不同手势的识别,所以引用了手势识别。

1、简单的复习一下View.OnTouchListener,它包含的触摸事件识别按下、移动和抬起。
2、onTouchEvent和onInterceptTouchEvent的理解。

onInterceptTouchEvent决定是否允许Touch事件继续向下(子控件)传递,一但返回True(代表事件在当前的viewGroup中会被处理),则向下传递之路被截断(所有子控件将没有机会参与Touch事件),同时把事件传递给当前的控件的onTouchEvent()处理;返回false,则把事件交给子控件的onInterceptTouchEvent()
OnTouchListener当前控件在处理完Touch事件后,是否还允许Touch事件继续向上(父控件)传递。返回false,则向上传递给父控件,详细一点就是这个touch事件就给了父控件,那么后面的up事件就是到这里touch触发,不会在传给它的子控件。如果父控件依然是false,那touch的处理就给到父控件的父控件,那么up的事件处理都在父控件的父控件,不会触发下面的。返回true,如果是子控件返回true,那么它的touch事件都在这里处理,父控件是处理不了,因为它收不到子控件传给他的touch,被子控件给拦截了。
我的理解是:返回true,消耗了该事件,就不再传递。返回false,未消耗该事件,会将事件传递下去

    @Override
    public boolean onTouchEvent(MotionEvent ev) { // 屏蔽touch事件,才能在监听其子控件的touch事件
        super.onTouchEvent(ev);
        return false;//与父控件,自己处理收是否向上传递该事件
    }

    @Override  
    public boolean onInterceptTouchEvent(MotionEvent event)// 屏蔽touch事件传递,才能在监听其子控件的touch事件
    {  
        super.onInterceptTouchEvent(event);  
        return false;  //决定Touch事件是否向子控件传递,未消费,给子控件的该方法
    } 

实验一:OnTouchEvent()事件学习

public class MyLinearLayout extends LinearLayout {

    public MyLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        int action = event.getAction();
        switch (action) {
        case MotionEvent.ACTION_DOWN:
            Log.i("hq", "-------------------ACTION_DOWN:----------------------");
            break;
        case MotionEvent.ACTION_MOVE:
            Log.i("hq", "-------------------ACTION_MOVE:----------------------");
            Log.i("hq", "X:"+event.getX()+"  Y:"+event.getY());
            break;
        case MotionEvent.ACTION_UP:
            Log.i("hq", "-------------------ACTION_UP:----------------------");
            break;
        default:
            break;
        }
        return super.onTouchEvent(event);//Touch事件传递给父控件处理
//      return true;//自己消费该事件,执行ACTION_MOVE,ACTION_UP
    }
}

当onTouch返回false时,事件传给它的父控件,打印的日志如下:
只接收到Action_Down

当onTouch返回true时,事件自行处理,打印的日志如下:

实验二:onInterceptTouchEvent()事件学习

布局:在重写的LinearLayout中添加一个按钮控件。

   <com.hq.gesturedetectordemo.MyLinearLayout 
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#C1FFC1"
        android:layout_margin="30dp">
        <Button 
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_margin="10dp"
            android:onClick="innerClick"
            android:text="按钮"/>
    </com.hq.gesturedetectordemo.MyLinearLayout>

更改onInterceptTouchEvent()方法返回值,查看效果。我们已经知道了,return true,就不会将该事件传给子view,return false 将让子view获得触屏事件,执行它的方法。验证图如下:

return true:view自己获得onTouch事件进行处理:
view自己获得onTouch事件进行处理

return false:将事件传递给子控件
将事件传递给子控件

GestureDetector 基础知识

重写的函数:

OnDown(MotionEvent e):用户按下屏幕就会触发;
onShowPress(MotionEvent e):如果是按下的时间超过瞬间,而且在按下的时候没有松开或者是拖动的,那么onShowPress就会执行,具体这个瞬间是多久,我也不清楚呃……
onLongPress(MotionEvent e):长按触摸屏,超过一定时长,就会触发这个事件
触发顺序:
onDown->onShowPress->onLongPress
onSingleTapUp(MotionEvent e):从名子也可以看出,一次单独的轻击抬起操作,也就是轻击一下屏幕,立刻抬起来,才会有这个触发,当然,如果除了Down以外还有其它操作,那就不再算是Single操作了,所以也就不会触发这个事件
触发顺序:
点击一下非常快的(不滑动)Touchup:
onDown->onSingleTapUp->onSingleTapConfirmed
点击一下稍微慢点的(不滑动)Touchup:
onDown->onShowPress->onSingleTapUp->onSingleTapConfirmed
onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) :滑屏,用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发
参数解释:
e1:第1个ACTION_DOWN MotionEvent
e2:最后一个ACTION_MOVE MotionEvent
velocityX:X轴上的移动速度,像素/秒
velocityY:Y轴上的移动速度,像素/秒
onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY):在屏幕上拖动事件。无论是用手拖动view,或者是以抛的动作滚动,都会多次触发,这个方法 在ACTION_MOVE动作发生时就会触发
滑屏:手指触动屏幕后,稍微滑动后立即松开
onDown—–》onScroll—-》onScroll—-》onScroll—-》………—–>onFling
拖动
onDown——》onScroll—-》onScroll——》onFiling
可见,无论是滑屏,还是拖动,影响的只是中间OnScroll触发的数量多少而已,最终都会触发onFling事件!

实现步骤:
1、
创建对象,已构造实例或构造类的方式。

GestureDetector.OnGestureListener listener = new GestureDetector.OnGestureListener(){ };   //构造实例

private class gestureListener implements GestureDetector.OnGestureListener{  
  //构造类
}  

2、根据构造函数创建实例对象
3、在view的onTouch事件中拦截手势

public boolean onTouch(View v, MotionEvent event) {
    return mGestureDetector.onTouchEvent(event);   
}

4、对用户手势的处理都在mGestureDetector的实现中。

 private class gestureListener implements GestureDetector.OnGestureListener{  

        public boolean onDown(MotionEvent e) {  
            Log.i("MyGesture", "onDown");     
            Toast.makeText(MainActivity.this, "onDown", Toast.LENGTH_SHORT).show();     
            return false;  
        }  

        public void onShowPress(MotionEvent e) {  
            Log.i("MyGesture", "onShowPress");     
            Toast.makeText(MainActivity.this, "onShowPress", Toast.LENGTH_SHORT).show();     
        }  

        public boolean onSingleTapUp(MotionEvent e) {  
            Log.i("MyGesture", "onSingleTapUp");     
            Toast.makeText(MainActivity.this, "onSingleTapUp", Toast.LENGTH_SHORT).show();     
            return true;     
        }  

        public boolean onScroll(MotionEvent e1, MotionEvent e2,  
                float distanceX, float distanceY) {  
            Log.i("MyGesture22", "onScroll:"+(e2.getX()-e1.getX()) +"   "+distanceX);     
            Toast.makeText(MainActivity.this, "onScroll", Toast.LENGTH_LONG).show();     

            return true;     
        }  

        public void onLongPress(MotionEvent e) {  
             Log.i("MyGesture", "onLongPress");     
             Toast.makeText(MainActivity.this, "onLongPress", Toast.LENGTH_LONG).show();     
        }  

        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  
                float velocityY) {  
            Log.i("MyGesture", "onFling");     
            Toast.makeText(MainActivity.this, "onFling", Toast.LENGTH_LONG).show();     
            return true;  
        }  
    };  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值