`
hyongbai
  • 浏览: 14550 次
文章分类
社区版块
存档分类
最新评论

android 如何 绘制 Views

 
阅读更多

当一个Activity获得了焦点后,它将被要求去绘制它的layout(也就是那句在onCreate方法里面的setContentView()方法所设置的layout)。android的framework会处理这个绘制的过程,但是这个Activity也必须提供这个将绘制的View的layout层级的根节点信息。

ps:这里需要解释下最后一句话。我们都知道,一个layout文件是一个包含了多个层级的xml文件。里面的各个xml节点信息就代表了一个又一个的layout层级——也就是这里所谓的“layout层级的根节点”。借由xml技术的本身特点,我们可以保证每个层级在layout中的唯一性,如此一来,我们就可以很方便地为我们即将绘制于某layout上的View进行绘制部位定位了。另外学过数据结构的同学应该知道,节点是数据结构“树”中的概念。所以根据这个,我推测,layout的xml文件信息被加载到内存中后,实际上是以一个“树”的形式存在的。

绘制某个View的工作从该View即将绘制的layout根节点开始。framework在这之前会预测量和绘制这个layout“树”。而绘制该layout“树”的工作则会这么做:遍历这个“树”,然后为每个占有了某个未使用区域的View预留出某个已知大小(该大小就是我们常常用到的layout_width和layout_height属性中所包含的信息)的区域供以后绘制View时使用。之后,各个ViewGroup会依次请求将它们的子View被绘制(通过ViewGoroup的draw方法),而每个View在被绘制的时候又会调用它自身的onDraw方法来把自身绘制出来。因为layout“树”是按顺序遍历的,这就意味着父View(例如ViewGroup)会在子View之前被绘制。

tips:framework不会绘制那些不在未使用区域的View,而且它会为View绘制背景。你可以强制性的去让一个View被绘制——通过利用invalidate()方法。

ps:绘制一个完整的layout的步骤大致如下:1、将layout.xml文件解析至内存,让这些layout信息以一个“树”的形式存在。2、framework遍历该“树”,从上到下依次绘制View。3、绘制View时,会在未使用的区域为即将绘制的该View预留空间,接着调用该View的draw方法来绘制它。

绘制一个layout包含了两大过程:一个是尺寸测试过程。该过程中会在layout“树”里自顶向下地对每个View进行尺寸测量。尺寸测量的工作由View类的measure(int, int)方法进行实现。在"树"遍历的工程中,每个View会调用该方法,然后通过读取一些开发者设定的信息(layout_height layout_width)来保存自己的尺寸信息。当尺寸测试过程进入尾声时,每一个View都已经保存了它的尺寸信息了。另一个过程就是具体的绘制了。在这个自顶向下遍历树的绘制过程中,每个父View会调用layout(int, int, int, int)方法,并结合子View在尺寸测量过程中所保存的尺寸信息,来安放该子View在自己内部的位置。

当一个View的measure方法返回时,它的width和height——以及它的子View的——属性必须已经被设定完毕。一个View的width和height必须遵从它的父View的相关尺寸约束——这样就保证了在尺寸测试过程尾声时,所有的父View都能够顺利的接受它们的子View。一个父View可能会在其子View上多次调用measure方法。例如,父View可能会先调用它的子View的measure方法来得知它们究竟多大,进而好为它们预留绘制空间,然后父View有接着会又调用measure来测试是否该尺寸适合该View。

tips:通过调用requestLayout()可以初始化一个layout的相关信息。这个方法通常是View在发觉自己的当前所处范围不适合自己的当前情况时被主动调用。

在尺寸测试过程中,有两个类比较重要。一个是View.MeasureSpec。它被View用来告诉它的父View自己想要是多大以及如何地被放置。另一个是我们已经很熟悉的LayoutParams,它仅仅描述了这个View的height和width的信息。对于height和width,可以被如下指定:

1、一个确切的像素值

2、FILL_PARENT,这个意味着该height 或width和父View的相同(减去padding的像素值)。

3、WRAP_CONTENT,这个意味着该View的height和width以刚好包含其内容为准。

各个ViewGroup有自己相应的LayoutParams子类来实现各自个性化的设置需求。例如RelativeLayout有它自己的LayoutParams子类来设定其子View的相对位置。

MeasureSpecs被用来将父View的需求传递给子View。它可以被设置为以下三种模式之一:

  • UNSPECIFIED,父View对子View的尺寸大小没有特殊要求。
  • EXACTLY,父View需要把子View设置为某个特定的像素值。子View必须为这个值,而且要保证它的所有子View也在这个尺寸之内绘制。
  • AT_MOST,告诉子View一个最小的尺寸值。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics