当前位置: 首页 > news >正文

(面试)View相关知识

1、View绘制流程

  • onMeasure() 确定View的测量宽高。
  • onLayout() 确定View的最终宽高四个顶点的位置。
  • onDraw() 将View 绘制到屏幕上。

2、MeasureSpec有三种测量模式:

2.1. EXACTLY(精确模式)

  • 含义:父容器明确指定了子View的精确尺寸,子View必须使用该尺寸
  • 典型场景:
    • 布局中设置了固定值(如android:layout_width="100dp")。
    • View的宽/高设置为match_parent,且父容器有确定尺寸。
  • View行为:必须直接使用MeasureSpec中的size作为最终尺寸。

2.2. AT_MOST(最大模式)

  • 含义:父容器指定了子View的最大可用尺寸,子View的尺寸不能超过该值,但可以更小

  • 典型场景:

    • View的宽/高设置为wrap_content

    • 父容器为ScrollViewRecyclerView等可滚动的容器。

  • View行为:根据自身内容计算尺寸,但最终尺寸不能超过MeasureSpec中的size


2.3. UNSPECIFIED(未指定模式)

  • 含义:父容器对子View无任何约束,子View可以自由决定尺寸(通常根据自身逻辑或内容)
  • 典型场景:
    • 自定义ViewViewGroup需要多次测量(如ListView测量子View的高度)。
    • 系统内部测量(如ScrollView在测量子View的滚动范围时)。
  • View行为:完全由自身决定尺寸(可能使用默认值或内容所需尺寸)。

3、事件分发机制

3.1 事件分发:dispatchTouchEvent

用来进行事件的分发,如果事件能够传递给当前View,则该方法一定会被调用。返回结果受当前View的onTouchEvent和下级的dispatchTouchEvent的影响,表示是否消耗当前事件。

原型:public boolean dispatchTouchEvent(MotionEvent ev)

return:

  • ture:当前View消耗所有事件
  • false:停止分发,交由上层控件的onTouchEvent方法进行消费,如果本层控件是Activity,则事件将被系统消费,处理

3.2 事件拦截:onInterceptTouchEvent

需注意的是在Activity,ViewGroup,View中只有ViewGroup有这个方法。故一旦有点击事件传递给View,则View的onTouchEvent方法就会被调用

在dispatchTouchEvent内部使用,用来判断是否拦截事件。如果当前View拦截了某个事件,那么该事件序列的其它方法也由当前View处理,故该方法不会被再次调用,因为已经无须询问它是否要拦截该事件。

原型:public boolean onInterceptTouchEvent(MotionEvent ev)

return:

  • ture:对事件拦截,交给本层的onTouchEvent进行处理
  • false:不拦截,分发到子View,由子View的dispatchTouchEvent进行处理
  • super.onInterceptTouchEvent(ev):默认不拦截

3.3 事件处理:onTouchEvent

在dispatchTouchEvent中调用,用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一事件序列中,当前View无法再接受到剩下的事件,并且事件将重新交给它的父元素处理,即父元素的onTouchEvent会被调用

原型:public boolean onTouchEvent(MotionEvent ev)

return:

  • true:表示onTouchEvent处理后消耗了当前事件
  • false:不响应事件,不断的传递给上层的onTouchEvent方法处理,直到某个View的onTouchEvent返回true,则认为该事件被消费,如果到最顶层View还是返回false,则该事件不消费,将交由Activity的onTouchEvent处理。
  • super.onTouchEvent(ev):默认消耗当前事件,与返回true一致。

事件分发机制总结:

在分析事件分发机制时,应该从事件分发的顺序入手一步一步解剖。从上文我们知道事件分发顺序为:Activity->Window->DecorView->ViewGroup->View。由于Window与DecorView可以看作是Activity->ViewGroup的过程,故这里将从三部分通过源码来分析事件分发机制:

  1. Activity对点击事件的分发机制
  2. ViewGroup对点击事件的分发机制
  3. View对点击事件的分发机制
  • 当一个点击事件发生后,总是先传递给当前的Activity,由Activity的dispatchTouchEvent进行分发,而Activity会将事件传递给Window,然后由Window的唯一实现类PhoneWindow将事件传递给DecorView,接着DecorView将事件传递给自己的父类ViewGroup,此时的ViewGroup就是通过setContentView所设置的View,故可以称为顶级View,这时候ViewGroup可能是自己处理该事件或者传递给子View,但是最终都会调用View的dispatchTouchEvent来处理事件。
  • 在View的dispatchTouchEvent中,如果设置了onTouchListener,会调用其onTouch方法,如果onTouch返回true,则不再调用onTouchEvent。如果有设置点击事件,则在onTouchEvent会调用onClick方法。如果子View的onTouchEvent返回了false,则表示不消耗事件,事件会回传给上一级的ViewGroup的onTouchEvent,如果所有的ViewGroup都没有返回true,则最终会回传到Activity的onTouchEvent。

4、requestLayout(), invalidate(), postInvalidate() 方法区别

requestLayout方法只会导致当前view的measure和layout,而draw不一定被执行,只有当view的位置发生改变才会执行draw方法,因此如果要使当前view重绘需要调用invalidate。

invalidate在UI线程中调用,postInvalidate在非UI线程中调用。因为android的UI线程是非线程安全的,所以在非UI线程中,需要使用postInvalidate来使View重绘。view调用invalidate将导致当前view的重绘(draw调用),view的父类将不会执行draw方法viewGroup调用invalidate会使viewGroup的子view调用draw,也就是viewGroup内部的子view进行重绘

http://www.xdnf.cn/news/504289.html

相关文章:

  • 【强化学习】#5 时序差分学习
  • BBR 的 buffer 动力学观感
  • C++(19):内联(inline)函数
  • Python跳动的双爱心
  • JAVA GUI
  • 【深度学习-Day 12】从零认识神经网络:感知器原理、实现与局限性深度剖析
  • 令牌桶和漏桶算法使用场景解析
  • HDCleaner:深度清理与优化,提升系统性能
  • 六、磁盘划分与磁盘配额
  • Redis 发布订阅模式深度解析:原理、应用与实践
  • AI:人形机器人一定是人的形状吗?
  • 超长文本能取代RAG吗
  • 计算机视觉与深度学习 | Python实现EMD-SSA-VMD-LSTM时间序列预测(完整源码和数据)
  • 深入探讨 Java Switch Expressions
  • 期望是什么:(无数次的均值,结合概率)21/6=3.5
  • AI大模型(一)embedding模型的基础使用
  • AGI大模型(21):混合检索之混合搜索
  • Git Worktree 使用
  • 【Einops】Einops rearrange方法详解
  • C# 创建线程的方式
  • 一字典两世界:优雅移除 `NSDictionary` 指定键的最佳实践
  • 编程基础:什么是变量
  • 《 C语言中const修饰指针变量的用法与解析》
  • 解决米勒补偿右边零点的方法
  • 【蓝桥杯省赛真题51】python石头运输 第十五届蓝桥杯青少组Python编程省赛真题解析
  • mcp学习笔记
  • day 28
  • ECS/GEM是半导体制造业的标准通信协议中host和equipment的区别是什么,在交互过程中,如何来定位角色谁为host,谁为equipment
  • Spring Boot 中 MyBatis 与 Spring Data JPA 的对比介绍
  • 【Python 算法零基础 3.递推】