View的工作原理

一、ViewRoot和DecorView


1、ViewRoot

1)ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带,View的三大流程均通过ViewRoot来完成。
2)在Activity线程中,当Activity对象被创建完毕后,会将DecorView添加到Window中,同时会创建ViewRootImpl对象,并将ViewRootImpl对象和DecorView建立连接。
3)View的绘制流程
  • -纵向:从ViewRoot的performTraversals开始->performMeasure->performLayout->performDraw
  • -横向
  •     -performMeasure->measure->onMeasure
  •     -performLayout->layout->onLayout
  •     -performDraw->draw->onDraw
    

2、DecorView

1)一般情况下,DecorView内部会包含一个LinearLayout,里面分为上下两部分,分别为标题栏和内容栏,我们设置布局的时候就是调用setContentView方法。
2)DecorView是一个FrameLyout,View层的事件都先经过它,然后分发给子View。

二、MeasureSpec


1、概念

MeasureSpec代表一个32位的int值,高2位代表SpecMode,低30位代表SpecSize。

1)SpecMode代表测量模式,有3种
  1. -UNSPECIFIED:父容器不对View有任何限制,要多大给多大。一般用于系统内部。
  2. -EXACTLY:父容器已经检测到View所需要的精确大小,这个时候View的最终大小就是SpecSize所指定的值。对应LayoutParams中的match_parent和具体的数值。
  3. -AT_MOST:父容器指定了一个可用大小即SpecSize,View的大小不能大于这个值。对应LayoutParams中的wrap_content。
2)SpecSize代表在某种测量模式下的规格大小。

2、MeasureSpec和LayoutParams的对应关系


1)DecorView
其Measure由窗口尺寸和自身Layoutparams来决定。调用getRootMeasureSpec方法,返回MeasureSpec
  •  -LayoutParams.MATCH_PARENT:窗口尺寸+EXACTLY
  •  -LayoutParams.WRAP_CONTENT:窗口尺寸+AT_MOST
  •  -默认:Layoutparams的尺寸+EXACTLY
 
2)普通View
其Measure由父容器的MeasureSpec和自身Layoutparams来决定。调用getChildMeasureSpec方法,返回MeasureSpec
  •  -parentSpecMode:EXACTLY
  •   -childLayoutParams.dp/px:child尺寸+EXACTLY
  •   -childLayoutParams.match_parent:parent尺寸+EXACTLY
  •   -childLayoutParams.wrap_content:parent尺寸+AT_MOST
  •  -parentSpecMode:AT_MOST
  •   -childLayoutParams.dp/px:child尺寸+EXACTLY
  •   -childLayoutParams.match_parent:parent尺寸+AT_MOST
  •   -childLayoutParams.wrap_content:parent尺寸+AT_MOST
  •  -parentSpecMode:UNSPCIFIED
  •   -childLayoutParams.dp/px:child尺寸+EXACTLY
  •   -childLayoutParams.match_parent:0
  •   -childLayoutParams.wrap_content:0

三、View的工作流程


1、measure过程

1)View的measure过程:
  •  -onMeasure:调用setMeasureDimension
  •  -setMeasureDimension:设置View宽高的测量值,参数通过getDefaultSize获取。 -getDefaultSize:返回measureSpec中的specSize,也就是View测量后的大小,第一个参数通过getSuggestedMinimumWidth/getSuggestedMinimumHeight获取,第二个参数为measureSpec。
  • -getSuggestedMinimumWidth/getSuggestedMinimumHeight:如果View没有设置背景,返回android:minWidth这个属性所指定的值,可以为0;如果View设置了背景,返回的就是View在UNSPECIFIED情况下的测量宽高。
2)ViewGroup的measure过程
ViewGroup是一个抽象类,并没有定义其测量的具体过程,而是提供了一个measureChildren的方法,具体过程需要各个子类去实现。

3)获取View的宽高:
因为measure过程和Activity的生命周期不同步,所以在onCreate、onStart、onResume中不能保证绝对获取到。

  • -onWindowFocusChanged:View已经初始化完毕,可以获取到View宽高。
  • -view.post(runnable):post将一个runnable投递到消息队列的队尾,然后等待Looper调用此runnable的时候,View已经初始化好了。
  • -ViewTreeObserver:使用ViewTreeObserver的回调,比如OnGlobalLayoutListener这个接口,当View树的状态发生变化或者View树内部的View可见性改变时,onGlobalLayout方法将被调用,这时就可以获取到View宽高。

2、layout过程

1)首先通过setFrame方法设定View的四个顶点的位置
2)调用onLayout方法,父容器确定子元素的位置。

3、draw过程

1)绘制背景:background.draw(canvas)
2)绘制自己:onDraw
3)绘制Children:dispatchDraw
4)绘制装饰:onDrawScrollBars

注意:
1)一个View不需要绘制内容,那么标志位 WILL_NOT_DRAW设为true,系统会自动进行优化。
2)默认情况下,View没有启用这个标志位,ViewGroup则默认启动。
3)当自定义控件继承自ViewGroup并且自身不具备绘制功能,就可以开启这个标志位,从而便于系统优化。

四、自定义View


1、自定义View的分类


1)继承View重写onDraw方法
实现一些不规则的效果,但是需要自己处理wrap_content和padding这两种情况。
2)继承ViewGroup派生特殊的Layout
实现几个View组合的效果,但是需要自己处理ViewGroup的measure和layout过程。
3)继承特定的View
用于扩展已有的View,不需要自己处理wrap_content和padding这两种情况。
4)继承特定的ViewGroup
实现几个View组合的效果,不需要自己处理ViewGroup的measure和layout过程。

2、自定义中的注意事项

  • 1)让View支持wrap_content和padding。
  • 2)尽量不要在View使用Handler。
  • 3)View中如果有线程或者动画,需要及时停止。
  • 4)处理好View中的滑动冲突。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值