Android UI | View 的绘制流程详解

Android UI | View 的绘制流程详解,第1张

上一篇文章讲解了,从setContentView方法到了解View是如何绘制的: 传送门

在这篇博客讲述了, 在ViewRootImpl类中performTraversals方法中具体的绘制过程,其中里面就有 performMeasure()、performLayout()、performDraw() 三个方法的调用, 那么要了解View 的测量、布局、绘制,就分别跟这三个方法有关系。

先来看看performMeasure()方法的调用过程

先看performMeasure方法,这个方法有两个参数,都是通过getRootMeasureSpec()方法计算得到

这里有一个关键类MeasureSpec,在这里需要了解下这个类的原理。

这里要感谢 这位博主 ,他讲述的很清晰,我自己动手测算了,很容易理解。大概就是用一个数字通过高位记录Mode,地位记录size的方式,记录两个数据,都是通过一个掩码做位移运算得来。就是说这个变量(measureSpec)的值可以通过掩码分别得到测量mode 和 测量size。

继续查看performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);方法:

这里mView是DecorView对象,那么他调用的实际上是View的measure方法,查询DecorView和FrameLayout都没有measure方法,所以他调用的是View的measure方法

DecorViewonMeasure()方法如下:

FrameLayoutonMeasure方法如下:(这个方法里面都很重要)

我们先看 , measureChildWithMargins 方法,

getChildMeasureSpec 方法内容如下:

那么假如我们写的布局根节点是LinearLayout,那么就会在执行到Viewmeasure方法里面的onMeasure方法时,就会调用到LinearLayoutonMeasure方法,具体内容如下:

通过源码可以看到,还是会循环调用子View , 就这样循环递归的测量完最里面的一个view,这个过程中onMeasure方法可能会被多次执行。

还是从ViewRootImplperformTraversals开始

这里跟measure 调用流程其实一样,DecorView和FrameLayout没有重写layout方法,所以调用的是Viewlayout方法,

由于当前对象是decorView,所以调用的是DecorViewonLayout方法:

FrameLayoutonLayout 方法如下:

继续查看 Viewdraw方法

在这个方法里面,所有重要的方法都在里面,onDraw、dispatchDraw 等等都在里面,我看了下这个方法里面都挺重要就没删减,也都能看得懂。

到此View的整个绘制流程就搞清楚了。

关于子view测量

1、不管父View是何模式,若子View有确切数值,则子View大小就是其本身大小,且mode是EXACTLY

2、若子View是match_parent,则模式与父View相同,且大小同父View(若父View是UNSPECIFIED,则子View大小为0)

3、若子View是wrap_content,则模式是AT_MOST,大小同父View,表示不可超过父View大小(若父View是UNSPECIFIED,则子View大小为0)

关于绘制流程

我们自定义的view,基本上只需要重写 onMeasure、onLayout、onDraw即可

如果子view是auto layout, 则会自动跟着父view变化,不需要相关设置

如果子view是frame布局,不管父view是frame布局还是auto layout布局,都需要相关设置才能跟着变化

父view需要设置 autoresizesSubviews , autoresizesSubviews 默认是 true ,可以不用设置

子view需要设置 autoresizingMask 属性

比如接着上篇 Android-View的事件分发及拦截机制简单流程先体验再研究(场景?疑问 具体?待续) ,小白现在要实现就是子View和父ViewGroup都响应点击事件。

1 单纯的都只是响应down事件

这个就很简单了 - 直接子View的public boolean onTouchEvent(MotionEvent event) 里面直接返回false就行了。也就是子控件响应了一次down后,接下来就交给父ViewGroup了(子View就啥几把也干不了了);

2 响应down和up事件,move啥的

我们知道子View如果onTouch里面返回了true,那么将会处理后续的move,up事件。而不再交给上层父ViewGroup。那父ViewGroup就没办法在Touch里面处理,所以我们只能放到dispatchTouchEvent或者onInterceptTouchEvent中处理这个down,up等事件:

比如dispatchTouchEvent中:

这样的情况就是父ViewGroup先执行点击事件,然后子View再执行。 如果您需要父ViewGroup晚点,可以延时执行啥的。

如果此时,子View的dispatchTouchEvent返回true - 表示拦截,不继续了

那么子View的所有的事件都不会响应了。其实也就是我们的一个事件先传递,touch再处理的树形图:

百度上拔个图来

简单记录下下而已,继续加深理解这是上一篇的续,还是上一篇啧啧后面是官方文档分析来着

 android事件分发机制 就是一个触摸事件发生了,从一个窗口传递到一个视图,再传递到另外一个视图,最后被消费的过程,在android中还是比较复杂的传递流程如下:

(1) 事件从ActivitydispatchTouchEvent()开始传递,只要没有被停止或拦截,从最上层的View(ViewGroup)开始一直往下(子View)传递。子View可以通过onTouchEvent()对事件进行处理。

(2) 事件由父View(ViewGroup)传递给子View,ViewGroup可以通过onInterceptTouchEvent()对事件做拦截,停止其往下传递。

以上就是关于Android UI | View 的绘制流程详解全部的内容,包括:Android UI | View 的绘制流程详解、iOS 子view随着父view的大小变化而变化、Android-View的事件分发及拦截-父控件和子控件都处理触摸事件的方式等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/10138162.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-05
下一篇 2023-05-05

发表评论

登录后才能评论

评论列表(0条)

保存