Android Touch System(一)

前言

之前写了一篇文章是关于自定义控件的。在学习自定义view的时候顺便把安卓的touch system(安卓触摸机制)也给系统学习了一遍。学习过程就是看了一个老外两个多小时的视频,是一位叫Dave Smith的大牛(安卓系统开发工程师)。不得不说,最新最好的东西来自国外。这篇文章算我对两个月前看这个视频之后的总结吧。


Android如何处理触摸事件

MotionEvent

我相信MotionEvent这个sdk提供的常量大家应该不陌生吧。这是android系统给我们封装好的用来存储touch事件的东西。它包含了很多你感兴趣的东西。比如触摸的时间,触摸的手指数,触摸的地点等等。。。而它又分为action_down, action_up等等很多类型。开发者可以通过这些名字来分别触摸事件的类别,我相信大家也用到过这些。

  • action_down 所有的触摸事件开始于这个。也就是你的手指触摸到屏幕的时候产生的事件。
  • action_up 所有的触摸事件终止于这个。也就是你的手指离开屏幕。
  • action_move 手指在屏幕滑动。
  • action_cancel 当一个view在消费某个事件的时候,如果你要把这个事件转给其他的view会用到这个。

以上时最基本的,也就是说,一个完整的手势定义就是开始于down,然后接受其他的事件,然后终止于up。周而复始。你自己新定义的手势必须遵循这个原则。


Android的事件分发机制

首先,清楚一点,你的activity优先于所有你的activity里面的view获得触摸事件。因为他是你的可视图的顶层。然后这个事件流会被activity的dispatchTouchEvent() 方法分发给自己的子view。这是系统框架自己做的事情。我们知道就好。如果子view里面又有viewgroup,那么这个viewgroup又会把事件流拿到分发给自己的子view。这就是一个视图结构树。

touch event.png

事件流会呈现一种从上到下,再从下到上的传递形式。我们讲到事件流会从activity由dispatchtouchevent向下传递。如果在传递在最底部的view的过程中还没有一个view宣布对这个事件感兴趣,那么事件将会从下到上又把这个事件传递给activity。但是如果这个过程中,某个view比如button宣布对这个action_down这个事件感兴趣了,那么这个事件流将不会再往下传递。这个时候如果你的手指拿开,就产生了一个action_up的事件。这个流就会直接传到当初你对action_down感兴趣的view去。这样极大的提高了安卓的效率。


Android的事件消费

这里说的事件消费也就是上面提到的view对某个事件是否感兴趣。实现机制就是在view里面调用onTouchEvent()方法,这个方法我相信很多人都遇到过的,它其实是对整个手势的事件流的监听。如果你想让一个view对某个事件感兴趣,那么判断如果遇到了这个事件,return true。表示你对这个事件感兴趣,那么事件的传递将会停止。并且需要记住的一点是activity的onTouchEvent() 方法是最后调用的。并不是第一个。

ViewGroup 对于事件分发给子view要复杂一点。如果你写过自定义view group,那你知道view group会对子view进行位置安排(on layout())。而当事件传到某个view group的时候,他会根据子view的位置来确定哪些子view对这个事件感兴趣。如果多个子view重叠,那viewgroup会根据子view加入view group的逆序来分发事件。

Android事件的窃取与反窃取

这里说的窃取是定义在viewgroup和他的子view之间的。举个例子

test.png

这里有一个srcollview作为view group,里面有个button作为子view。

  1. 用手指去按下button。这里button宣布对这个事件感兴趣了。嗯,好的,button儿子准备接受up事件,然后顺利产生一次点击事件了
  2. 滑动手指。卧槽,什么,怎么又滑动手指了,产生了一个move事件。我们都知道,这样做了之后,button将不会在被点击,也就是说他接收不到up的事件了,为什么呢,因为他的爸爸scrollview把这个事件给窃取了。坑儿子哈哈
  3. 儿子不听话,非要完成这次点击。于是儿子来了一次反窃取,阻止爸爸偷本属于自己的up事件。于是采取了反窃取手段达成目的。

很容易理解了吧。窃取就是在viewgroup里面调用onInteceptTouchEvent()。还记得前面讲的那个action_cancel吧,如果move事件被窃取,那么button酒会收到一个cancel的事件,告诉button你不会再收到接下来的其他事件了。反窃取就是在button里面调用requestDisallowTouchIntercept(Boolean boolean)如果传true,那么就阻止了view group去窃取这个手势。

来看一下源码吧。

onInterceptTouchEvent(Motion m)

ViewGroup中
@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return super.onInterceptTouchEvent(ev);
    }
源码中:
  * @param ev The motion event being dispatched down the hierarchy.
     * @return Return true to steal motion events from the children and have
     * them dispatched to this ViewGroup through onTouchEvent().
     * The current target will receive an ACTION_CANCEL event, and no further
     * messages will be delivered here.
     */
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return false;
    }

很清楚了吧。大家可以再看一遍源码的注视!一目了然。默认是false,如果重写return true就可以窃取了。

requestDisallowIntercept(Boolean is)

/**
     * Called when a child does not want this parent and its ancestors to
     * intercept touch events with
     * {@link ViewGroup#onInterceptTouchEvent(MotionEvent)}.
     *
     * <p>This parent should pass this call onto its parents. This parent must obey
     * this request for the duration of the touch (that is, only clear the flag
     * after this parent has received an up or a cancel.</p>
     *
     * @param disallowIntercept True if the child does not want the parent to
     *            intercept touch events.
     */
    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept);

在源码中可以看到,一旦对一个事件表示了不允许parent窃取(注意我说的是一个事件,而不是事件流),那么会设置一个flag,标志知识这个事件不允许parent窃取。但是这个flag会在parent收到这个事件的up活着cancel的时候,就会重置flag。onInterceptTouchEvent()是一样的道理,不同的是这个方法是需要传入一个具体的MotionEvent的。还有一点值得提的是,如果你的viewgroup里面的所有子view都对down这个事件不感兴趣,但是某个view却对up感兴趣。那么你一定要在viewgroup的onTouchEvent()方法里面返回true。不然viewgroup的parent不会再把之后的事件传给viewgroup了哦!!


总结

好啦,对于android触摸事件的基础知识也了解的差不多可以了。未完待续!~

版权声明:本文为博主原创文章,未经博主允许不得转载。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容