Android 用户界面和视图绘制
View对象是Android平台中用户界面体现的基础单位。View类是它称为“widgets(工具)”的子类的基础,它们提供了诸如文本输入框和按钮之类的UI对象的完整实现。
ViewGroup类同样为其被称为“Layouts(布局)”的子类奠定了基础,它们提供了象流式布局、表格布局以及相对布局之类的布局架构。
View对象是一个数据体,它的属性存储了用于屏幕上一块矩形区域的布局参数及内容。并负责这块它所辖的这个矩形区域之中所有测量、布局、焦点转换、卷动以及按键/触摸手势的处理。作为一个用户界面对象,View同时也担任着用户交互关键点以及交互事件接受者的角色。
视图层次View Hierarchy在Android平台上,你可以用下图所示的View和ViewGroup层次图来定义一个 Activity的UI。这个层次树可随你所愿的简单或者复杂化,你能使用Android预定义的一套工具和布局来创建它,或者使用你自己定义的 Views来创建。
为了把一个视图层次树展现到屏幕上,你的Activity必须调用setContentView()方法 ,并传给它一个根节点对象的引用。Android系统将接受此引用,并用来进行界面的废止、测量并绘制这棵树。层次的根节点会要求它的子节点进行自我绘制 ──进而,每个视图组节点也负责调用它的子视图进行自我绘制。子节点将向父节点申请绘制的位置以及大小,而其父类享有子节点绘制的位置及大小的最终决定权。Android依次(自层次树顶层开始)解析你布局中的元素,实例化View并将它们添加到它们的父节点中。因为这个过程是依次进行的,所以如果出现了元素重叠的情况,最后一个绘制的元素将位于所有重叠元素之上显现。
Android怎么绘画视图How Android Draws Views
当一个活动接收到焦点时,它将被要求绘制它的布局。Android框架将处理这个绘画的过程,但是活动必须提供它的布局层次的根节点。
绘画从布局的根节点开始。它被要求来测量和绘制布局树。绘画通过遍历布局树并渲染每个和失效区域相交的视图来处理。相应的,每个视图组负责请求绘制它的子视图(通过draw() 方法)而每个视图负责画它自己。因为这个树是顺序遍历的,这意味着先画父节点(也就是在屏幕后面),然后按照树中出现的顺序画其同层次节点。
Android的框架只绘制有效区中的视图,并同时处理视图的背景。你也可以使用invalidate()方法强制绘
制。
绘画布局共有两步:一个度量过程和一个布局过程。度量过程在measure(int, int)里实现且是一个自顶向下的视图树遍历。每个视图在递归时往下推送尺寸规格。在度量过程的最后,每个视图都已经保存了自己的度量。第二个过程发生在layout(int, int, int, int) 中并且也是自顶向下。在这个过程中,每个父节点负责定位它的所有子节点,通过使用在度量过程中计算得到的尺寸。
当一个视图的measure()方法返回时,它的getMeasuredWidth()和getMeasuredHeight() 值必须被设置,以及所有这个视图子节点的值。一个视图的度量的宽度和高度值必须符合父视图引入的限制。这确保在度量过程之后,所有父节点接受所有它们的子节点的度量值。一个父视图可能会在其子视图上多次调用measure()方法。比如,父视图可能会通过未指定的尺寸调用measure来发现它们的大小,然后使用实际数值再次调用measure(),如果所有子视图未做限制的尺寸总合过大或过小(也即是,如果子视图之间不能对各自占据的空间达成共识的话,父视图将会干预并设置第二个过程的规则)。
measure pass使用两个类来传递尺寸,View使用View.MeasureSpec 类告诉其父视图自己的尺寸以及位置,
最基本的LayoutParams类只用来描述视图的宽和高,对每个尺寸,可以有下面三种方式指定。
? 一个具体的数字
? FILL_PARENT, 这个意思是当前View要和其父视图同样大小(减去padding的值)
? WRAP_CONTENT, 这个意思是当前视图只需要包围其内容即可(包含padding)。
要初始化一个布局的时候,需要调用requestLayout()方法,该方法被调用的典型场景是一个View觉得其自
身不在适应当前规定的范围的时候。
对于不同的ViewGroup子类,有相应的LayoutParams子类。比如,相对布局RelativeLayout有它自己的LayoutParams子类,这包含了能够让子视图横向和竖向居中显示的能力。
度量规格(MeasureSpecs)被用来沿着树从父到子的下传度量需求。一个MeasureSpecs可以是下面三种模式之一:
· UNSPECIFIED: 这被父视图用来决定其子视图期望的尺寸。比如,一个线性布局可能在它的子视图上调用measure() on its child,通过设置其高度为UNSPECIFIED 以及一个宽度为EXACTLY 240,来找出这个子视图在给定240像素宽度的情况下需要显示多高。
· EXACTLY: 这被父视图用来给子视图强加一个准确的尺寸。子视图必须使用这个大小,并确保其所有的后代将适合这个尺寸。
· AT_MOST: 这被父视图用来给子视图强加一个最大尺寸。子视图必须确保它自己以及所有的后代都适合这个尺寸。