Android自定义ViewGroup的那些事儿

47e1f2af99dce68ce7c44ca08bf73d2e.png

 cde28c42f333678a6c79f39d74cb5c90.gif 

本文字数:2463

预计阅读时间:7分钟

概念

ViewGroup是一种可以包含其他视图的特殊视图,他是各种布局和所有容器的基类,这些类也定义了ViewGroup.LayoutParams类作为类的布局参数, ViewGroup是容器,用来包含其他控件。ViewGroup需要重写onMeasure方法测量子控件的宽高和自己的宽高,然后实现onLayout方法摆放子控件。

绘制原理

android 坐标系:以屏幕左上角作为原点,这个原点向右是X轴的正轴,向下是Y轴正轴,如图所示:

16eac8484e9f941427fd2680d6e224fd.png

View坐标系,View坐标系内部关系如图所示:

8d966672f7e0d5d2f0e96953d453c40a.png

流程图如下所示:

d817256a90b709811a0dd857894164e4.png

从上图,我们可以理出大致的显示过程如下:

  1. ActivityManagerService创建Activity线程,激活一个activity。

  2. 系统调用Instrumentation.newActivity创建一个activity。

  3. Activity创建后,attach到一个新创建的phonewindow中。这样Activity获取一个唯一的WindowManager服务的实例。

  4. Activity创建过程中使用setcontentView设置用用户UI,这些VIEW被加入到PhoneWindow的ContentParent中。

  5. Activity线程继续执行,当执行到Activity.makeVisible是将根view DecoView加入到WindowManger中,WindowManger实全会为每个DecoView创建对应的ViewRoot。

  6. 每个ViewRoot拥有一个Surface,每个Surface将会调用底层库创建图形绘制的内存空间。这个底层库就是SurfaceFlinger。SurfaceFlinger同时也负责将个View绘制的图形合到一块(按照Z轴)显示到用户屏幕。

  7. 如果用户直接在Canvas上绘制,实际上它直接操作Surface。但对每个View的变更,它是要通知到ViewRoot,然后 ViewRoot获取Canvas。如果绘制完成,surfaceFlinger得到通知,合并Surface成一个Surface到设备屏幕。从上面的图形输出过程分析,我们可以知道真正显示图形的实际上跟Activity没有关系,完全由WindowManager来决定。WindowManager是一个系统服务,因此可以直接调用这个服务来创建界面,并且更绝的是Dialog、Menu也是有WindowManager 来管理的。另外一个我们也可以看到,最底层都是Surface来,因此,常见开发游戏的人都推荐你使用SurfaceView来创建界面。

详细绘制流程如下:整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简单概况为根据之前设置的状态,判断是否需要重新计算视图大小(measure)、是否重新需要安置视图的位置(layout)、以及是否需要重绘 (draw),其框架过程如下:

b1e6a2207923a36e929a2b4bdecb8619.png

接下来温习一下整个View树的结构,对每个具体View对象的操作,其实就是个递归的实现。

a4f23e27f05f737decf0e3fdb54df5fa.png

绘制流程

  1. 继承ViewGroup,覆盖构造方法。

  2. 重写onMeasure方法测量子控件和自身宽高。

  3. 实现onLayout方法摆放子控件。

  4. 在onDraw()方法中,绘制子控件,可有可无。

  5. 监听onTouch事件,响应屏幕触摸事件。相应思维导图如下图所示:

    15dd84a0c61203ec4891d2933de99933.png

Measure

Measure过程还是测量ViewGroup的大小,如果layout_widht和layout_height是match_parent或具体的xxxdp,就很简答了,直接调用setMeasuredDimension()方法,设置ViewGroup的宽高即可,如果是wrap_content,就比较麻烦了,我们需要遍历所有的子View,然后对每个子View进行测量,然后根据子View的排列规则,计算出最终ViewGroup的大小。onMeasure方法的源码如下:

9eaec7761f5e9a45765bb3601fc7c539.png

setMeasu

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值