View体系的一些小问题|青训营笔记

简介: 设置点击事件逻辑的时候,最基础的办法就是先用 findViewById() 来绑定实例,其次就是设置一个匿名内部类来监听点击,继而处理事件。

问题

设置点击事件逻辑的时候,最基础的办法就是先用 findViewById() 来绑定实例,其次就是设置一个匿名内部类来监听点击,继而处理事件。那么我们可以提出以下的问题。

  1. 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;
}
复制代码
  1. 从上述的代码可以看出,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;
    }
复制代码
  1. ViewGroup 是继承自 View 的,直接使用了 View 的 findViewById() 方法,所以只复写了 ViewGroupfindViewTraversal()。其处理逻辑是,迭代查看它的哪个子View符合,然后返回;否则返回 null。
  2. 我们常重写的 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;
    }
复制代码
  1. 在上文我们知道 onClick() 方法是通过上述代码标注1处来设置的,可知手指离开屏幕的时候,此处执行的是普通的点击事件。
    下面我们说下普通点击和长按点击分别如何执行。现在我们再看回标注3,此处执行的是 checkForLongClick() ,即一点击屏幕就会执行该方法,该方法会开启一个线程来计时和处理 onLongClick()。然后就看到条件为手指离开屏幕处的标注2,此处是判断此时是否已经执行了 onLongClick(),若是未执行,就说明是未能到达触发条件,此时移除不执行长按事件。移除后,就会去到标注3处,执行 onClick() 普通的点击事件。
  2. 常用的交互事件和触摸事件有哪些
    交互事件
    1.webp.jpg
    上文方法中的 onTouch()onClick() 之类的方法的关系是前者包含后者,包括 onLongClick() 都是基于此封装的。onTouch() 是他们的入口。
    触摸事件

1.webp.jpg

相关文章
|
运维 架构师 测试技术
架构师成长日记 - 01 4+1视图模型
架构师成长日记 - 01 4+1视图模型
219 0
架构师成长日记 - 01 4+1视图模型
|
Dubbo Java 应用服务中间件
使用Kitex框架构建自己的服务|青训营笔记
这篇文章主要跟随官方文档给出自己使用Kitex构建一个服务的过程,而后续Kitex更多的特性则需要大家深入学习、实践、总结。
549 0
使用Kitex框架构建自己的服务|青训营笔记
|
Android开发
View体系(上)|青训营笔记(一)
View 体系是较为复杂的,但是又非常重要的一个知识点。我们把这部分知识吃透吃熟是十分必要的,打卡第一天,我把View体系的第一部分知识整理出来,快来和我一起学习吧。
View体系(上)|青训营笔记(一)
|
XML 数据格式
View体系(上)|青训营笔记(二)
View 体系是较为复杂的,但是又非常重要的一个知识点。我们把这部分知识吃透吃熟是十分必要的,打卡第一天,我把View体系的第一部分知识整理出来,快来和我一起学习吧。
View体系(上)|青训营笔记(二)
|
异构计算
View体系(下)|青训营笔记
熟悉完 View 的基础,了解完其分发流程,事件分发的传递规则。我们需要深入理解 View 的工作流程,包括绘制原理以及三大方法的流程,洞悉其原理和实现。
View体系(下)|青训营笔记
带你封装MVP架构(下)|青训营笔记(二)
在 Base 类中,我们需要做的就是把每个 Activity 或者 Fragment 等这些组件,或者对应的 MVP 层会用到的基本操作以及联系都编写好。
|
前端开发 Android开发
带你封装MVP架构(上)|青训营笔记(一)
我们做一个 MVP 架构的封装,主要其相对于MVC更加解耦,能让开发人员在编写代码的时候更加高效和舒服。
|
前端开发 API
带你封装MVP架构(上)|青训营笔记(二)
我们做一个 MVP 架构的封装,主要其相对于MVC更加解耦,能让开发人员在编写代码的时候更加高效和舒服。
|
JSON 数据处理 Android开发
带你封装MVP架构(下)|青训营笔记(一)
在 Base 类中,我们需要做的就是把每个 Activity 或者 Fragment 等这些组件,或者对应的 MVP 层会用到的基本操作以及联系都编写好。
|
JSON 小程序 API
小程序开发-第三章第二节下拉刷新,上拉加载-全栈工程师之路-中级篇
小程序开发-第三章第二节下拉刷新,上拉加载-全栈工程师之路-中级篇
101 0
小程序开发-第三章第二节下拉刷新,上拉加载-全栈工程师之路-中级篇