问题
设置点击事件逻辑的时候,最基础的办法就是先用 findViewById()
来绑定实例,其次就是设置一个匿名内部类来监听点击,继而处理事件。那么我们可以提出以下的问题。
findViewById()
如何找到并绑定对应的 View
首先,findViewById()
会做一个层层代理,执行到DecorView
这一层的findViewById()
中。
然后,DecorView
本质上是ViewGroup
,那么就变成了在ViewGoup
上寻找对应的View
。
由于ViewGroup
是继承自View
的,我们先来查看View
的代码
//View public <T extends View> T findViewById(@IdRes int id) { if(id == NO_ID){ return Null; } return findViewTraversal(id); } public <T extends View> T findViewTraversal(@IdRes int id) { if(id == mID){ return (T)this; } return null; } 复制代码
- 从上述的代码可以看出,View 中如果 id 不存在就会返回null;如果存在且等于自己,就会返回自己。
下面我们来看 ViewGroup 中的代码
//ViewGroup /** * {@hide} */ @Override protected <T extends View> T findViewTraversal(@IdRes int id) { if (id == mID) { return (T) this; } final View[] where = mChildren; final int len = mChildrenCount; for (int i = 0; i < len; i++) { View v = where[i]; if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) { v = v.findViewById(id); if (v != null) { return (T) v; } } } return null; } 复制代码
ViewGroup
是继承自View
的,直接使用了 View 的findViewById()
方法,所以只复写了ViewGroup
的findViewTraversal()
。其处理逻辑是,迭代查看它的哪个子View符合,然后返回;否则返回 null。- 我们常重写的 onClick() 是和 onLongClick() 他们同时设置的话会同时执行吗?执行逻辑有何不同?
这两个方法如何执行的,我们需要查看它的源码
//View public boolean onTouchEvent(MotionEvent event) { ... if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { switch (action) { case MotionEvent.ACTION_UP: mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; ... if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { ... if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { // This is a tap, so remove the longpress check removeLongPressCallback();//标注2 // Only perform take click actions if we were in the pressed state if (!focusTaken) { // Use a Runnable and post this rather than calling // performClick directly. This lets other visual state // of the view update before click actions start. if (mPerformClick == null) { mPerformClick = new PerformClick();//标注1 } if (!post(mPerformClick)) { performClickInternal(); } } ... mIgnoreNextUpEvent = false; break; case MotionEvent.ACTION_DOWN: ... if (!clickable) { checkForLongClick(//标注3 ViewConfiguration.getLongPressTimeout(), x, y, TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); break; } ... break; ... } return true; } return false; } 复制代码
- 在上文我们知道
onClick()
方法是通过上述代码标注1处来设置的,可知手指离开屏幕的时候,此处执行的是普通的点击事件。
下面我们说下普通点击和长按点击分别如何执行。现在我们再看回标注3,此处执行的是checkForLongClick()
,即一点击屏幕就会执行该方法,该方法会开启一个线程来计时和处理onLongClick()
。然后就看到条件为手指离开屏幕处的标注2,此处是判断此时是否已经执行了onLongClick()
,若是未执行,就说明是未能到达触发条件,此时移除不执行长按事件。移除后,就会去到标注3处,执行onClick()
普通的点击事件。 - 常用的交互事件和触摸事件有哪些
交互事件
上文方法中的onTouch()
和onClick()
之类的方法的关系是前者包含后者,包括onLongClick()
都是基于此封装的。onTouch()
是他们的入口。
触摸事件