android view的工作原理

目录

1.ViewRoot和DecorView

2.MeasureSpec

3.view测量布局绘制过程

①.测量过程(measure过程)

②.布局过程

③.绘制过程(根据官网有详细步骤,如下)

4.自定义view

①自定义view须知

②.示例自定义view(画一个圆形的view)

③.示例自定义ViewGroup(实现类似横向滑动的ViewGroup)

5.getMeasuredWidth()与getWidth()函数区别


1.ViewRoot和DecorView

①ViewRoot的PerformTraversals方法开始最终调用view的measure、layout、draw方法。

decorview最终分为有titlebar和content两个布局,我们平时设置的setcontentview布局就是content这一块的,titlebar是标题栏actionBar的那部分。

2.MeasureSpec

①.MeasureSpec代表32位int值高2位代表SpecMode低30位代表SpecSize

②.SpecMode:测量模式(分为:UNSPECIFIED(无限大小)、EXACTLY(精准大小)、AT_MOST(可用大小))

③.SpecSize:某种测量模式下的规格大小

④.decorView的MeasureSpec由本身的LayoutParams决定的,对应关系:

LayoutParams.MATCH_PAREMT:精准模式EXACTLY

LayoutParams.WRAP_CONTENT:最大模式AT_MOST

固定大小(比如:100dp):精准模式EXACTLY

⑤.普通view的MeasureSpec由父容器的MeasureSpec和本身的LayoutParams决定的,对应关系如下:

parentSpecSize

ChildLayoutParams      

EXACITY

AT_MOST

UNSPECIFIED

dp/px

EXACITY

childSize

EXACITY

childSize

EXACITY

childSize

match_parent

EXACITY

parentSize

AT_MOST

parentSize

UNSPECIFIED

0

wrap_content

AT_MOST

parentSize

AT_MOST

parentSize

UNSPECIFIED

0

3.view测量布局绘制过程

①.测量过程(measure过程)

view的onMeasure方法中直接调用serMeasuredDimension方法设置测量大小。

注意:当父布局SpecMode是AT_MOST时此处的子布局wrap_content和match_parent的值一样,可以重写onMeasure方法给wrap_content设置默认值和match_parent区分

viewGroup的onMeasure方法未实现,需要根据布局重写此方法:

步骤:(1)测量子view  (2)测量自身

LinearLayout中来说:

(1)通过measureChildWithMargins方法测量子view的大小。

(2)通过setMeasuredDimension方法结合子view的状态测量本身view的值。(此处当是wrap_content时,高度是子view高度之和;采用match_parent或者具体数值则和测量view的一致)。

注意:View的measure过程和生命周期不是同步执行的,所以可能在oncreate,onStart,onResume中无法获取宽高。

解决方式:(1)通过onWindowFocusChanged方法,此方法表示view加载完毕。

                  (2)通过view的post方法,此方法在view初始化完成的尾部执行。

                  (3)通过ViewTreeObserver回调接口功能。

                  (4)手动调用view的measure方法进行测量。

对比发现:(1)(3)会被多次调用,(4)写起来比较麻烦,对match_parent还测量不出,所以(2)是最好的方式。

注意:控件测量的结果只是为正式布局提供建议,至于用不用,要看onLayout

②.布局过程

父布局通过layout方法最终调用setFrame方法确认自己的位置。

父布局调用onLayout最终通过for循环调用setChildFrame方法确认子view的位置。

③.绘制过程(根据官网有详细步骤,如下)

*      1. Draw the background
*      2. If necessary, save the canvas' layers to prepare for fading
*      3. Draw view's content
*      4. Draw children
*      5. If necessary, draw the fading edges and restore layers
*      6. Draw decorations (scrollbars for instance)

第二步(保存图层)和第五步(绘制阴影效果)可以跳过,所以步骤如下:

(1)绘制背景;(drawBackground)

(2)如有需要,保存图层;

(3)绘制view;(onDraw)

(4)绘制子view;(dispatchDraw)

(5)如有需要,绘制阴影效果;

(6)绘制装饰;(ondrawScrollBars)

注意:在view中有setWillNotDraw是表示是否绘制的,如果不用绘制可以设置为true,这样便于系统优化,如果需要绘制设置为false。

4.自定义view

①自定义view须知

(1).让view或者viewGroup支持wrap_content。

(2).让自定义view支持margin需要重写generateLayoutParams()函数和generateDefaultLayoutParams()函数,因为只有重写这两个函数才能获取控件的margin值

(3).让自定义view支持padding,需要在onDraw里面处理padding;让自定义viewGroup支持padding,需要在onMeasure和onLayout考虑到padding和子元素margin对其影响。

(4).不要在view中用handler,view本身的post系列方法可以替代handler作用。

(5).view中有线程或者动画需要及时停止,可以在onDetachedFromWindow方法中做停止操作。

(6).view中有镶嵌滑动需要处理好滑动冲突。

②.示例自定义view(画一个圆形的view)

(1).复写onDraw(canvas)方法实现画圆

(2).在onMeasure(widthMeasureSpec,heightMeasureSpec)方法中处理wrap_content情况。

(3).在onDraw(canvas)中处理padding情况

③.示例自定义ViewGroup(实现类似横向滑动的ViewGroup)

(1).复写onMeasure(widthMeasureSpec,heightMeasureSpec),在这里面测量view及子view,需要考虑到padding及子view的margin的影响。

(2).复写onLayout确定子元素的位置,需要考虑到padding及子view的margin的影响。

(3).处理滑动嵌套冲突问题。

5.getMeasuredWidth()与getWidth()函数区别

大部分情况下上面两个函数获取得到的值相同,但是含义不一样

①.获取得到的时间点不一样:getMeasuredWidth()函数在measure()过程结束后就可以获取到宽度值,而getWidth()函数要在layout()过程结束后才能获取得到的宽度值。

②.获取的值设置方式不同:getMeasuredWidth()函数中的值是通过setMeasuredDimension()函数来进行设置的;而getWidth()函数中的值则是通过layout(left,top,right,bottom)函数来设置的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龚礼鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值