zoukankan      html  css  js  c++  java
  • onTouch

    OnTouch
    OmOnTouchListener
    OnTouchEvent

    View的事件分发 :
        对于事件分发机制,举个简单的例子,在一个Activity中只有一个按钮,如果我们想给这个按钮注册一个点击事件,只需要调用setOnClickListener方法,这样在onClick方法里
        面写实现的代码,就可以在按钮被点击的时候执行.我们再给这个按钮添加一个touch事件,只需要调用setOnTouchListener方法,onTouch方法里能做的事情比onClick要多一
        些,比如判断手指按下、抬起、移动等事件。如果我两个事件都注册了,我之前做过一个实验,运行程序点击按钮的结果是onTouch是优先于onClick执行的,并且onTouch执行
        了两次,一次是ACTION_DOWN,一次是ACTION_UP(你还可能会有多次ACTION_MOVE的执行,如果你手抖了一下)。因此事件传递的顺序是先经过onTouch,再传递到onClick。
        onTouch方法是有返回值的,如果我们尝试把onTouch方法里的返回值改成true,再运行一次就会发现onClick方法不再执行了,这是因为onTouch方法返回true就认为这个事件
        被onTouch消费掉了,因而不会再继续向下传递。


    1、为什么要有事件分发机制
        如果ViewGroupA里面包含一个ViewGroupB,ViewGroupB里面再包含一个view,
        当点击view的时候,为什么只有view相应事件,点击的也是A的区域。
        这就引发了事件分发机制

    2、MotionEvent主要有几个事件类型、
        down
        move
        up

    3、事件分发的主要方法
        分发事件:
            dispatchTouchEvent(View,ViewGroup:view 之间touch事件传递的入口函数 onInterceptTouchEvent:判断 touch 事件是否拦截 onTouchEvent:处理 touch 事件)
            如果返回true/false,则表示事件传递到这儿就终止了,不会继续分发
            也不会传给父级

        拦截事件:onInterceptTouchEvent
            只有ViewGroup有这个方法,只有子类才需要拦截。返回true,表示拦截该事件
            就不会分发给子类。

        消费事件:onTouchEvent
            Touch 事件 ACTIONDOWN, ACTIONUP ,ACTIONMOVE, ACTIONCANCLE
            返回true,这个事件被消费掉了,就不会再传给出去了。如果没有人消费掉,则最终
            会被当前的activity消耗掉,下次的move和up事件就不会在传下去了。

        注意:
            一个down事件分发之后,还有回传的过程。因为一个事件分发包括down、move、
            up这个几个动作,当手指触碰到屏幕那一刻,首先分发down事件,事件分发完之
            后还要回传回去,然后继续从头开始分发,执行下一个move操作,知道执行完up
            事件,整个分发过程到此结束。

            当自定义viewgroup时不会拦截down事件,一旦拦截,后边的move和up就不会再
            传递下去了。事件以后只会传给viewgroup这里。

        事件一旦分发到view则默认一定会执行他的onTouchEvent分发
            父view把touch 事件传递给子view 处理,是调用了子view 的 dispatchTouchEvent 方法
            子view的 dispatchTouchEvent 方法把 touch 事件交给两个兄弟负责:
            mOnTouchListener.onTouch 方法
            onTouchEvent 方法
            先是让 onTouch 方法处理 touch 事件,如果 onTouch 方法消耗掉 touch 事件,那么 dispatchTouchEvent 方法直接返回 true;如果 onTouch 方法没有消耗掉
            touch 事件,那么调用 onTouchEvent 方法来处理 touch 事件,此时 dispachTouchEvent 方法的返回值,就靠 onTouchEvent 方法来决定。

    列举:
        A包括B,B包括C(view)详解:
        1、点击c,c不消费事件
        当一个事件产生后,传递流程是  activity --> phoneWindow --> view
        当点击c的时候,事件从mainActivity的事件分发开始,然后去问b是否消费事件,然后将事件
        分发给B,事件到了B,他不拦截事件,先去问自己的孩子要不要消费事件,然后发给c,事件
        到了view,开始执行dispatchevent方法来决定是否消费事件。
        事件回传, c不消费事件,所以它开始回传,告诉B我不消费事件(view的onTouchEvent返回false),然
        后B才有权利决定是否消费该事件,这时开始执行onTouchEvent事件,B也不消费事件,所以
        onTouchEvent也返回false,事件继续传给A的onTouchEvent方法,由于A也不消费,最终扔给
        了mainActivity去消费。

        2、点击C,view消费掉事件
        mainActivity一层一层往下传,到了view便开始执行onTouchEvent方法来决定是否消费该事件,
        由于view消费掉了这个事件,view的onTouchEvent便return false,B收到通知view消费了事
        件,所以就不会执行B的onTouchEvent事件,只能回传告诉A,view消费了事件,你没机会了。
        A收到return true后,就知道事件被消费了,所以他也return true,最终事件传给
        了mainActivity,由于事件被消费了,所以不会执行mainActivity的onTouchEvent方法,
        接下来执行Move事件,流程和之前的一样,重新开始执行。
        结论:onTouchEvent被view消费掉,A、B的onTouchEvent都不会执行。

        3、点击B,但是B不消费事件。
        B和A都不消费事件,最终只能交给mainActivity了去消费了。
        view的mOnTouchListener.onTouch方法优先于view的onTouchEvent方法。
             onTouchEvent 方法主要实现了 3 个功能:
             1. 根据 touch 事件产生 click 事件,调用 onClickListener.onclick 方法
             2. 根据 touch 事件产生 press 状态的变化
             3. 根据 touch 事件产生 焦点分发
        
    view和viewgroup对onTouchEvent事件的处理什么不同和联系?



    代码说明:

    请父级View不拦截touch事件:

        1.解决SwipeLayout和ListView的触摸事件冲突问题
            @Override
            public boolean onTouchEvent(MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        mDownX = event.getRawX();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        float deltaX = event.getRawX() - mDownX;
                        if(Math.abs(deltaX) > mHelper.getTouchSlop()){
                            getParent().requestDisallowInterceptTouchEvent(true);//请父级View不拦截touch事件
                        }
                        break;
                    case MotionEvent.ACTION_UP:
                        mDownX = 0;
                        break;
                }
                try {
                    mHelper.processTouchEvent(event);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return true;
            }

    touch事件分发的三个问题:

        1. onTouch和onTouchEvent有什么区别,又该如何使用?
            从源码中可以看出,这两个方法都是在View的dispatchTouchEvent中调用的,onTouch优先于onTouchEvent执行。如果在onTouch方法中通过返回true将事件消费掉,
            onTouchEvent将不会再执行。
            另外需要注意的是,onTouch能够得到执行需要两个前提条件,第一mOnTouchListener的值不能为空,第二当前点击的控件必须是enable的。因此如果我们有一个控件
            是非enable的,那么给它注册onTouch事件将永远得不到执行。对于这一类控件,如果我们想要监听它的touch事件,就必须通过在该控件中重写onTouchEvent方法来实
            现。

        2. 为什么给ListView引入了一个滑动菜单的功能,ListView就不能滚动了?
            如果你阅读了http://blog.csdn.net/guolin_blog/article/details/8744400 滑动菜单的功能是通过给ListView注册了一个touch事件来实现的。如果我们在onTouch方
            法里处理完了滑动逻辑后返回true,那么ListView本身的滚动事件就被屏蔽了,自然也就无法滑动(原理同前面例子中按钮不能点击),因此解决办法就是在onTouch方法
            里返回false。

        3. 为什么图片轮播器里的图片使用Button而不用ImageView?
            提这个问题的朋友可看看http://blog.csdn.net/guolin_blog/article/details/8769904 这篇文章。这篇文章里,在图片轮播器里使用Button,主要就是因为Button是  
            可点击的,而ImageView是不可点击的。如果想要使用ImageView,可以有两种改法。第一,在ImageView的onTouch方法里返回true,这样可以保证ACTION_DOWN之后的其
            它action都能得到执行,才能实现图片滚动的效果。第二,在布局文件里面给ImageView增加一个android:clickable="true"的属性,这样ImageView变成可点击的之后
             ,即使在onTouch里返回了false,ACTION_DOWN之后的其它action也是可以得到执行的。


    ZHBJ中...
    触摸事件的处理:
        我认为触摸事件的处理实质上就是重写控件的  
        dispatchTouchEvent(),
        onInterceptTouchEvent(),
        onTouchEvent()方法
        处理控件的分发,拦截,触摸的逻辑,用以达到我们想要的目的.以我之前做过的项目为例,
        其中比较难的有两个,一个是三次ViewPager嵌套,一个是ScrollView嵌套ViewPager再嵌套Viewpager和ListView

        >>>>>>>
        你看这个项目,它就是有三次ViewPager嵌套    
        他的最外层界面其实是一个VIewPager(其实它也可以用Fragment来做,不过我考虑到他是要不断切换界面这点和ViewPager的特点很像于是就用VIewPager来做了),我重写了它
        的onTouchEvent()方法,只返回true,屏蔽了它的滑动事件,并且设置了切换界面不滑动的属性,
        这点比较有意思,同样实现相同的功能,

        用ViewPager做我们就想屏蔽它的界面切换效果,用fragment来做又想自己给它添加一个界面切换的动画).然后把界面的切换交给了界面下方的四个单选按钮实现(这个功能的
        实现方法有很多,可以写四个TextView,然后drawableTop画上图片或者用线布局上面放ImageView下面放TextView实现都可以,只是考虑到功能需求是只能单选,和单选按钮的
        功能最为相似,用它做最简单,

        所有我使用一个RadioGroup嵌套四个RadioButton并且设置Radiobutton的button属性为null取消单选按钮的圆圈,drawableTop画上图片,给图片和字体颜色设置选择器实现的)
        ,并且把它的拦截事件onInterceptTouchEvent()方法重写返回false,让它不拦截子View的触摸事件(这个方法在ViewGroup中实现都比较简单,都是直接返回false,不过ViewPa
         ger和ListView都重写了这个方法,做了大量的逻辑和判断).

        其次,社区界面的发现和关注也是用ViewPager实现的,由于它的父控件的onInterceptTouchEvent()拦截方法已经被我重写并且返回false,所以它可接收到父控件传递过来的
        触摸事件并对其处理,所以我并没有对这层ViewPager做什么特殊的处理,直接使用了系统V4包里原生的ViewPager

        然后这个ViewPager里面的布局实际是一个Listview,前面几个比较特殊的界面是作为头布局添加进去的,这个头布局以及listview的条目中都有VIewPager的存在,这种情况就
        比较复杂了,
        因为这种ViewPager有很多控件都和它争抢触摸事件,比如它的父控件,listview,于是我做了这样的处理,首先ViewPager肯定是上下滑动不了的,然后只要ViewPager不是最后
        一个条目,我左右滑动都可以切换当前ViewPager,如果是最后一个条目的话,我再向右滑就可以切换父控件的ViewPager.所以我就重写了它的dispatchTouchEvent方法(),(虽然
        这里只有父ViewPager两个条目,但是我还是按照有多数pager的情况下写的以防以后业务发生改变,增加了条目),如果不是上下滑动,第一个条目右滑,最后一个条目左滑,我请
        求父控件不阻拦其触摸事件,让这个ViewPager处理滑动事件否则就不让父控件不阻拦,让父控件走自己的逻辑.

        而这个项目是我协助我朋友做的,它涉及到ScollView嵌套ViewPager,它这里面还用到了很多自定义控件
     

  • 相关阅读:
    Web 性能优化
    js 校验身份证
    html5 输入框响应enter按键
    获取浏览器的可视窗口宽高
    js打开新标签
    Java数据脱敏框架
    Spring Boot中的事务管理
    运维监控知识体系
    git常用命令图解 & 常见错误
    安全团队不可错过的七个云安全开源工具(转载)
  • 原文地址:https://www.cnblogs.com/dubo-/p/6680040.html
Copyright © 2011-2022 走看看