android事件如何分发给子view
来源:互联网 发布:sai软件中文版 编辑:程序博客网 时间:2024/05/16 18:14
哈哈,第一次使用markdown,看着挺高大上的啊。如果顺手了,会直接切换默认为markdown。
话说关于android事件分发的博客真的不在少数,基本都是基于源码分析+实例代码的形式讲解。今天的这篇博客呢,主要的侧重点并不是在事件分发上,而是在事件的转换上。
为什么需要事件转换? 打个比方吧:
我们点击一个TextView的左上角,加入这个TextView在它老子的中间位置,那我们点击的x/y应该是多少呢? 在它老子那这两个值可能是100/100,而在TextView上打印就会是1/1了,也就是说在事件分发给儿子之前会有一次事件的剪裁过程,这个过程稍后我们也会在源码中找到。
大家都知道事件的分发都是从 dispatchTouchEvent()
方法开始的,但是我们一般很少去重写 dispatchTouchEvent
方法,原因就是尽量避免破坏android原生的事件分发机制。但是今天我们就来试这重写一下 dispatchTouchEvent
方法,从最简单的代码探究事件的剪裁。(做好心理准备, 就两行代码)。
public class MyViewGroup extends LinearLayout { private View mFirstView; public MyViewGroup(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onFinishInflate() { super.onFinishInflate(); mFirstView = getChildAt(0); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { boolean handled = false; float x = ev.getX(); float y = ev.getY(); System.out.println("老子:x = " + x + ", y = " + y); if(x < mFirstView.getLeft() || x > mFirstView.getRight()) return true; if(y < mFirstView.getTop() || y > mFirstView.getBottom()) return true; int offetX = getScrollX() - mFirstView.getLeft(); int offetY = getScrollY() - mFirstView.getTop(); ev.offsetLocation(offetX, offetY); handled = mFirstView.dispatchTouchEvent(ev); ev.offsetLocation(-offetX, -offetY); return handled; }}
代码很简单,我们只需要关注dispatchTouchEvent
方法就ok, 可以看到 在dispatchTouchEvent
方法中,我们并没有任何 super.dispatchTouchEvent
的调用地方,也就是说,我们完全重写了android默认的事件分发机制。
现在我们来分析一下这段的代码。
前面的略过,21行代码打印了我们触摸的坐标。
23~24行,我们先不去管它。先去看下面的代码。
26~28行代码:
int offetX = getScrollX() - mFirstView.getLeft();int offetY = getScrollY() - mFirstView.getTop();ev.offsetLocation(offetX, offetY);
首先我们计算了offsetX和offsetY值,这两个值为什么要这么计算得出呢,我是怎么知道要这么计算的呢? 这里的答案是:看的android源码的事件剪裁~~~ 我是直接copy出android的源码来放这的,然后咱们再去理解他,要去理解它,我们还需要一张生动形象高端大气的图才ok。
来看图, scrollX代表这绿色部分在屏幕外面的部分,假如这里是50,
left是蓝色部分距离他老子(绿色部分)左边的值,即getLeft
这里是100,
当我们触摸屏幕的时候,坐标是从屏幕的左上角开始计算,从这张图来看,我们触摸的位置在绿色部分其实是50(100 - 10)的位置.
ok,在来看看offsetX
如果还是拿这张图来说的话, offsetX = 50 - 100 = -50
。offsetY的值也相同。
说到这里,我们大概明白MotionEvent.offsetLocation
的作用了,它的作用就是根据你的两个参数去偏移坐标。这里,我们的x偏移了-50,计算一下,如果将这个剪裁后的事件分发给子view,那对于子view而言,点击的位置就是0了。哈哈,终于走通了。
那接下来,我们就通过log来验证咱们的猜想吧。
看log验证了我们的猜想,事件的坐标的确是经过了剪裁。
而,我们代码中那两个判断:
if(x < mFirstView.getLeft() || x > mFirstView.getRight()) return true;if(y < mFirstView.getTop() || y > mFirstView.getBottom()) return true;
主要作用就是防止该事件没有发生到该view身上,而强制分发出去了。
最后,我们再去看看源码中是怎么操作的,是不是和我们的逻辑一样。
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel, View child, int desiredPointerIdBits) { final boolean handled; ... ... ... // If the number of pointers is the same and we don't need to perform any fancy // irreversible transformations, then we can reuse the motion event for this // dispatch as long as we are careful to revert any changes we make. // Otherwise we need to make a copy. final MotionEvent transformedEvent; if (newPointerIdBits == oldPointerIdBits) { if (child == null || child.hasIdentityMatrix()) { if (child == null) { handled = super.dispatchTouchEvent(event); } else { final float offsetX = mScrollX - child.mLeft; final float offsetY = mScrollY - child.mTop; event.offsetLocation(offsetX, offsetY); handled = child.dispatchTouchEvent(event); event.offsetLocation(-offsetX, -offsetY); } return handled; } transformedEvent = MotionEvent.obtain(event); } else { transformedEvent = event.split(newPointerIdBits); } // Perform any necessary transformations and dispatch. if (child == null) { handled = super.dispatchTouchEvent(transformedEvent); } else { final float offsetX = mScrollX - child.mLeft; final float offsetY = mScrollY - child.mTop; transformedEvent.offsetLocation(offsetX, offsetY); if (! child.hasIdentityMatrix()) { transformedEvent.transform(child.getInverseMatrix()); } handled = child.dispatchTouchEvent(transformedEvent); } // Done. transformedEvent.recycle(); return handled; }
看18~22行,代码和我们的一样!!!(其实是我们抄的源码,哈哈)。完结。
哦,对了,本篇博客并没有什么实质性的意义,就是去探究一下android事件在分发过程的剪裁,树立一个思想:
对于view而言,事件发生到我身上,我就把它看作我自己的,你点我拿,我就给你报哪。
在实际代码中,我们还是尽可能的避免重写dispatchTouchEvent
方法,毕竟这里是android默认的事件分发机制。
真正完毕了,吃饭去鸟~~~
- android事件如何分发给子view
- android 事件分发 View
- android View 事件分发
- android view 事件分发
- Android View事件分发
- android View事件分发
- android View 事件分发
- Android View 事件分发
- android view事件分发
- Android事件分发详解(七)——将事件分发至特定的子View.
- Android dispatchTouchEvent View事件分发
- android View事件分发机制。
- Android View的事件分发
- Android View事件分发机制
- android view事件分发机制
- Android View 事件分发机制
- Android:View事件分发机制
- Android View事件分发处理
- MFC对进程权限的提升
- sysdba不能远程登录,我们该怎么做
- 感染性的木马病毒分析之样本KWSUpreport.exe
- Unity3D事件函数的执行顺序
- POJ 2151 Check the difficulty of problems (概率DP)
- android事件如何分发给子view
- mini2440系统移植篇之kernel启动流程
- PHP3.2配置文件使ini文件配置
- 第十二周程序阅读5
- STM32频率计算——捕获方式
- centos7 下Apache服务器配置
- 用java开发学生信息管理系统(SIMS,三)
- 2015年百度测试开发实习生面试
- 多线程编程技术之NSThread、Cocoa NSOperation、GCD