当前位置: 首页 > 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进行重绘

相关文章:

  • STM32F103定时器1每毫秒中断一次
  • 如何 naive UI n-data-table 改变行移动光标背景色
  • Web3开发工具与框架全解析:从入门到实战
  • 角点特征:从传统算法到深度学习算法演进
  • 深度学习中独热编码(One-Hot Encoding)
  • 国内AWS CloudFront与S3私有桶集成指南:安全访问静态内容
  • MUSE Pi Pro 开发板 Imagination GPU 利用 OpenCL 测试
  • Python异常模块和包
  • 【Ragflow】22.RagflowPlus(v0.3.0):用户会话管理/文件类型拓展/诸多优化更新
  • python四则运算计算器
  • HarmonyOS NEXT~鸿蒙应用上架指南:HarmonyOS应用发布全流程解析
  • ABP vNext 多租户开发实战指南
  • Docker入门指南:镜像、容器与仓库的核心概念解析
  • Vue.js 教学第三章:模板语法精讲,插值与 v-bind 指令
  • 阿里云国际站与国内站的核心布局与本土化服务的选择
  • 人工智能-自然语言与语音产品实现
  • 【学习心得】英伟达的诸多显卡性能对比
  • 局部放大maya的视图HUD文字大小的方法
  • Go语言 Gin框架 使用指南
  • Java Stream流:高效数据处理的现代解决方案
  • 浙江一家长称小学老师打孩子还威胁要从3楼扔下,当地警方已立案
  • “80后”萍乡市安源区区长邱伟,拟任县(区)委书记
  • 中国进出口银行:1-4月投放制造业中长期贷款超1800亿元
  • 既是工具又是食物,可食用机器人开启舌尖上的新科技
  • 警方通报男子广州南站持刀伤人:造成1人受伤,嫌疑人被控制
  • 今年有望投产里程已近3000公里,高铁冲刺谁在“狂飙”?