Android View(View的工作原理)

1.AndroidUI管理系统的层级关系

UI管理系统的层级关系示意图

1.1.主要对象介绍

(1)PhoneWindow:Android系统中最基本的窗口系统,继承自Window类,负责管理界面显示以及事件响应,是Activity和View系统交互的接口。
(2)DecorView:PhoneWindow中的起始点View,继承于View类,作为整个视图容器使用,用于设置窗口属性,本质上是一个FrameLayout。
(3)ViewRoot:在Activity启动时创建,负责管理布局,渲染窗口UI

1.2.ViewRoot与DecorView

ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带,View的三大流程均通过ViewRoot来完成,在ActivityThread中,Activity被创建以后,会将DecorView添加到Window中,同时创建ViewRootImpl对象,并将ViewRootImpl对象和DecorView建立关联(通过ViewRoot的setView方法)。

1.3.View的绘制流程

View的绘制流程是从ViewRoot的PerformTraversals方法开始的,经过measure,layout,draw三个过程最终将一个View绘制出来。

  • measure(测量):测量View的宽高。
  • layout(布局):确定View在父布局中的放置位置。
  • draw(绘制):负责将View绘制在屏幕上
    performTraversals工作流程
    performTraversals会依次调用performMeasure,performLayout,performDraw三个方法,这三个方法分别完成顶级View的measure,layout,draw三大方法。measure方法中又会调用onMeasure方法,在此方法中会对所有元素进行measure过程,此时measure流程就从父容器传递到子元素中,一次measure过程就完成了,子元素会重复父容器的measure过程如此反复就完成了整个view树的遍历。performLayout和performDraw的传递过程是在draw方法中通过dispatchDraw方法完成的。
(1)measure过程

measure过程分为两类,普通的View通过measure方法后就完成了它的测量过程,而ViewGroup除了自己的测量过程外,还会遍历所有子元素的measure方法,子元素再递归执行。
View的measure过程:是一个final方法,不可重写,在该方法中会调用onMeasure方法。onMeasure方法中会调用getDefaultSize方法返回测量后的View的大小,getDefault方法中会调用getSuggestedWidth和getSuggestedHeight方法(这两个方法在没有指定背景的情况下,返回的是minSize这一属性对应的值,在指定了背景的情况下,返回的是背景的getMinimumWidth/getMiniumHeight方法对应的值)。View的宽高由specSize决定,因此直接继承自View的控件需要重写onMeasure方法并设置wrap_content时自身的大小否则在布局文件中使用wrap_content就相当于使用match_parent。
ViewGroup的measure过程:ViewGroup除了完成自己的measure过程,还会遍历调用子元素的measure方法,然后子元素再递归执行。ViewGroup是一个抽象类,因此没有重写View的onMeasure方法,但他提供了measureChildren方法,他会取出子元素的LayoutParams,通过getChildMeasureSpec方法创建子元素MeasureSpec,然后传递给View的measure方法进行测量,ViewGroup没有定义具体的测量过程具体测量过程的onMeasure需要子类来实现,由于子类特性可能很大不同,无法统一处理。(一般获取View宽高可以在onWindowFocusChanged中获取,此时View已经测量完毕了)

(2)layout过程

Layout的作用是ViewGroup用来确定子元素的位置,当ViewGroup的位置被确定后,他在onLayout中会遍历所有子元素并调用其layout方法,在layout方法中onLayout方法又会被调用,layout方法确定view的位置,onLayout方法确定所有子元素位置。
layout方法的流程:首先通过setFrame方法来设定View的四个顶点的位置即初始化mLeft,mRight,mTop,mBottom这四个值,View的四个顶点确定,在父容器中的位置也就确定了,接着会调用onLayout方法,父容器来确定子元素的位置,onLayout方法的实现和具体布局有关。

(3)draw过程

view的绘制过程主要分为四步

  • 绘制背景background.draw(canvas)
  • 绘制自己onDraw
  • 绘制children(dispatchDraw)
  • 绘制装饰(onDrawScollBars)
    view绘制过程的传递是通过diapatchDraw实现,该方法会遍历调用所有子元素的draw方法这样draw方法就能一层层传递下去了。
    setWillNotDraw:如果一个view不需要绘制任何内容,在我们设定这个标记为true时,系统会做相应的优化,view一般不启用,viewgroup默认启用自定义控件继承自viewGroup并且不具备绘制功能时,可以开启这个标记方便系统进行优化

1.4.MeasureSpec

MeasureSpec代表一个32位的int值,高两位代表SpecMode(测量模式),低30位代表SpecSize(在某种测量模式下的规格大小)
SpecMode有三类:

  • UNSPECIFIED:父容器不对view有任何限制要多大给多大,通常用于系统内部
  • EXACTLY:父容器已经检测出view所需要的精确大小,此时view最终大小就是SpecSize所指定的值,对用于LayoutParams中的match_parent和具体数值这两种模式
  • AT_MOST:父容器指定了可用大小SpecSize,View的大小不能大于这个值,具体是什么值要看不同的view的具体实现,对应于LayoutParams中的wrap_content
    在这里插入图片描述
    对于普通view,其MeasureSpec由父容器的MeasureSpec由父容器的MeasureSpec和自身的LayouParams共同决定
  • View采用固定宽高时:不管父容器的MeasureSpec是什么,View的MeasureSpec都是精确模式并且大小遵循LayoutParams中的大小
  • 当view的宽高是match_parent时:如果父容器是精准模式,那么view也是精准模式并且其大小是父容器的剩余控件。
  • 父容器是最大模式:view是最大模式且大小不会超过父容器的剩余空间
  • view宽高是wrap_content时:不管父容器的模式是精准还是最大化,view的模式总是最大化,并且大小不超过父容器的剩余空间。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值