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

目录
打赏
0
0
0
0
97
分享
相关文章
Axios请求成功和失败时分别执行哪个函数?
Axios请求成功和失败时分别执行哪个函数?
DeepSeekV2-lite 昇腾8卡训练实验指导
昇腾8卡运行deepseek-v2训练
122 1
最佳进度跟踪工具推荐:如何提高工作效率并按时完成任务?
本文介绍了6款高效的项目进度跟踪工具,包括Banli Kanban、TeamGantt、ZenHub、LiquidPlanner、Smartsheet和Redmine,详细阐述了它们的特点、适用场景及推荐理由,旨在帮助团队根据自身需求选择最合适的工具,提升项目管理效率和团队协作能力。
最佳进度跟踪工具推荐:如何提高工作效率并按时完成任务?
通义灵码 SWE-GPT:从 静态代码建模 迈向 软件开发过程长链推理
在本文中,作者介绍了 Lingma SWE-GPT,一款专为解决复杂软件改进任务设计的开源大型语言模型系列。
364 30
iOS自动化测试方案(五):保姆级VMware虚拟机安装MacOS
详细的VMware虚拟机安装macOS Big Sur的保姆级教程,包括下载VMware和macOS镜像、图解安装步骤和遇到问题时的解决方案,旨在帮助读者顺利搭建macOS虚拟机环境。
624 3
iOS自动化测试方案(五):保姆级VMware虚拟机安装MacOS
WPF开发者必读:揭秘ADO.NET与Entity Framework数据库交互秘籍,轻松实现企业级应用!
【8月更文挑战第31天】在现代软件开发中,WPF 与数据库的交互对于构建企业级应用至关重要。本文介绍了如何利用 ADO.NET 和 Entity Framework 在 WPF 应用中访问和操作数据库。ADO.NET 是 .NET Framework 中用于访问各类数据库(如 SQL Server、MySQL 等)的类库;Entity Framework 则是一种 ORM 框架,支持面向对象的数据操作。文章通过示例展示了如何在 WPF 应用中集成这两种技术,提高开发效率。
261 0
Linux 三剑客 grep、sed、awk
Linux三剑客`grep`、`sed`和`awk`是强大的文本处理工具。`grep`用正则表达式搜索匹配行;`sed`是流式编辑器,处理文本流而不直接修改原文件;`awk`则用于灵活的文本分析和报告生成。例如,`grep`可查找匹配模式,`sed`可以删除文件内容,而`awk`能提取特定字段。通过组合使用,它们能高效解决复杂文本任务。
155 1
JavaScript 中的 Range 和 Selection 对象
JavaScript 中的 `Range` 和 `Selection` 对象用于处理文本选择。`Range` 表示文档中选定的区域,而 `Selection` 表示用户选择的文本或光标位置。`Range` 可以创建并设置于任何元素或文本,具有多个属性(如 `startContainer`, `endContainer`, `collapsed`)和方法(如 `cloneContents`, `deleteContents`)。`Selection` 提供了获取和操作用户选择的方法,如 `anchorNode`, `focusNode` 和 `addRange`。两者在所有现代浏览器中基本兼容。
154 1
JavaScript 中的 Range 和 Selection 对象
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等