Flex企业应用开发实践学习笔记(四)-------组件的布局


布局过程被划分为三个界限清晰的阶段:提交阶段(commit phase)度量阶段(measurement phase)布局阶段(layout phase)。每个阶段都只有在处理完所有失效的组件后才会进入到下一个阶段。在某个阶段对组件进行处理时,组件可能会产生一些应该在前面阶段中处理的请求,这些请求将被排队,等到下一次执行到那些阶段时再进行处理。下面分别阐述每个阶段所完成的处理。


(1)提交阶段

提交阶段就是提交组件已变化的属性。在Flex中,组件的某个属性值的变更可能会影响到其他属性值。比如组件的scaleX属性,该属性表示组件在水平方向的拉伸比例,如果该属性发生变化,那么组件的explicitMinWidth、explicitWidth、explicitMaxWidth、width等属性都会根据该属性重新计算。而且在更新显示之前,scaleX属性可能会被频繁地更改。针对这样的属性,为了提高性能,开发者不应在组件属性的setter方法中立即计算与之相关的其他属性值,而是调用组件的invalidateProperties()方法将该组件标记为属性失效,从而使计算相关属性值的处理延迟到布局的提交阶段。

提交阶段从布局管理器调用自己的validateProperties()方法开始,在这个方法中,布局管理器按照组件嵌套层次的“由外到内”的顺序遍历“属性失效组件队列”中的组件,调用每个“属性失效组件”的validateProperties()方法。也就是说,最外层的“属性失效组件”的validateProperties()方法会最先被调用,如果Application对象的属性也失效了,那么它的validateProperties()方法会最先被调用,这个遍历顺序又称为“自顶向下”。

“属性失效组件”的validateProperties()方法会调用该组件的commitProperties()方法来完成与“失效属性”相关的其他属性值的计算。commitProperties()方法是一个protected方法,组件开发者应在自定义的UIComponent子类中重载这个方法,完成与失效组件属性相关的其他属性值计算。

UIComponent类中的commitProperties()方法处理scaleX属性的过程如代码清单2-20所示, 阅读这段代码有助于开发者了解自定义组件中重载commitProperties()方法应进行哪些处理。

代码清单2-20   UIComponent类的commitProperties()方法处理scaleX属性的代码片段

 
 
  1. protected function commitProperties():void  
  2. {  
  3. if (_scaleX != oldScaleX)  
  4.  {  
  5.      var scalingFactorX:Number = Math.abs(_scaleX / oldScaleX);  
  6.        if (!isNaN(explicitMinWidth))  
  7.             explicitMinWidth *= scalingFactorX;  
  8.        if (!isNaN(explicitWidth))  
  9.             explicitWidth *= scalingFactorX;  
  10.        if (!isNaN(explicitMaxWidth))  
  11.             explicitMaxWidth *= scalingFactorX;  
  12.             _width *= scalingFactorX;  
  13.             super.scaleX = oldScaleX = _scaleX;  
  14.         }  
  15. ......  
  16. }

(2)度量阶段

所谓度量(measurement)就是计算组件的默认尺寸。如果开发者没有设置任何与组件高度和宽度相关的属性,布局管理器就需要确定默认高度和宽度,否则无法完成布局。在设计人机界面时,我们经常从组件面板中拖放组件到界面设计器上。这时我们没有设定任何与组件尺寸有关的属性,但是组件能够以一个比较合适的尺寸展示出来,这就是组件度量所起的作用。

度量阶段从布局管理器调用自己的validateSize()方法开始。在这个方法中,布局管理器按照组件嵌套层次的“由内到外”的顺序遍历“尺寸失效队列”中的组件,调用每个“尺寸失效组件”的invalidateSize()方法。也就是说,越在外层的“尺寸失效组件”的invalidateSize()方法越后被调用。如果Application对象的尺寸也失效了,那么它的invalidateSize()方法最后被调用,这个遍历顺序又称为“自底向上”。

“尺寸失效组件”的invalidateSize()方法会调用该组件的measure ()方法来确定“尺寸失效组件”的默认大小。组件的measure ()方法是一个protected方法,组件开发者应在自定义的UIComponent子类中重载这个方法,完成组件默认尺寸相关属性的设置和计算。在这个方法中,主要是确定和计算measuredMinWidth、measuredMinHeight、measuredWidth、measuredHeight等表示最小默认宽度、最小默认高度、默认宽度、默认高度的属性值。下面是UIComponent类中measure()方法的代码片段,而实际上在确定组件的默认尺寸时可能会考虑到皮肤、样式等很多因素,因此可能会相当复杂。

 
 
  1. protected function measure():void  
  2. {  
  3.         measuredMinWidth = 0;  
  4.         measuredMinHeight = 0;  
  5.         measuredWidth = 0;  
  6.         measuredHeight = 0;  

(3)布局阶段

布局就是根据组件最新的属性、样式以及默认尺寸来更新组件显示列表中子显示对象的尺寸、位置并画出组件所使用的所有皮肤(skins)及图形化元素。组件的尺寸由其容器组件所确定。

布局阶段从布局管理器调用自己的 validateDisplayList()方法开始,在这个方法中,布局管理器按照组件嵌套层次的“由外到内”的顺序遍历其内部“显示列表失效组件队列”中的组件,调用每个“显示列表失效组件”的validateDisplayList()方法。也就是说,越在外层的“尺寸失效组件”的validateDisplayList ()方法越先被调用,如果Application对象的尺寸也失效了,那么它的validateDisplayList ()方法最先被调用,这个遍历顺序又称为“自顶向下”。

“显示列表失效组件”的validateDisplayList()方法会调用该组件的updateDisplayList()方法来更新组件“显示列表”中的“子显示对象”。组件的updateDisplayList()方法是一个protected方法,组件开发者应在自定义的UIComponent子类中重载这个方法,完成组件显示列表的更新处理。即确定内部对象的位置、尺寸以及画出组件使用的所有皮肤和图形化元素。

代码清单2-21显示了mx.controls.Label组件的updateDisplayList方法,阅读这段代码有助于开发者了解在自定义组件中重载updateDisplayList ()方法应执行哪些操作。

代码清单2-21   mx.controls.Label组件的updateDisplayList方法代码片段

 
 
  1. override protected function  
  2. updateDisplayList(unscaledWidth:Number,unscaledHeight:Number):void  
  3. {  
  4. super.updateDisplayList(unscaledWidth, unscaledHeight);  
  5.         // textField 占据了Label除去边白(padding)的所有区域  
  6.         var paddingLeft:Number = getStyle("paddingLeft");  
  7.         var paddingTop:Number = getStyle("paddingTop");  
  8.         var paddingRight:Number = getStyle("paddingRight");  
  9.         var paddingBottom:Number = getStyle("paddingBottom");  
  10.         textField.setActualSize(unscaledWidth - paddingLeft - paddingRight,  
  11. unscaledHeight - paddingTop - paddingBottom);  
  12.         textField.x = paddingLeft;  
  13.         textField.y = paddingTop;  
  14.         //现在处理文本容纳不下的截断情况。  
  15.         var t:String = isHTML ? explicitHTMLText : text;  
  16.         // 确定显示整个文本需要多大的textField。  
  17.         var textFieldBounds:Rectangle = measureTextFieldBounds(t);  
  18.         // 普通文本使用 "..."作为截断部分的显示符号。HTML文 本则直接被截断,因为跳过HTML标记只  
  19. 截断非标记文本比较困难。但是,如果普通文本和HTML文本不能完 全显示,那么会自动获得一个tooltip。  
  20.         if (truncateToFit)  
  21.         {  
  22.             var truncated:Boolean;  
  23.             if (isHTML)  
  24.             {  
  25.                 truncated = textFieldBounds.width > textField.width;  
  26.             }  
  27.             else  
  28.             {  
  29.            //用前面使用"..."作为截断符号的文本重设Label的文本。  
  30.                 textField.text = _text;  
  31.        //根据TextField的尺寸确定整个文本是否需要被截断,注意, 实际尺寸并未发生变化,只是改变文本内容来适应实际尺寸。  
  32.                 truncated = textField.truncateToFit();  
  33.             }  
  34. // 如果开发者没有显式设置tooltip那就隐式地设置tooltip或者清除tooltip。  
  35.             if (!toolTipSet)  
  36.                super.toolTip = truncated ? text : null;  
  37.         }  

以上就是组件生命周期与布局的主要过程,为了进一步帮助开发者掌握如何布局的相关内容,接下来我们探讨一下与布局相关的组件尺寸属性及其相互关系。

(4)与布局相关的组件尺寸属性

在组件布局中我们多次谈到了组件的尺寸,也知道组件的尺寸就是指组件的高度和宽度,本书有时也将组件尺寸称为组件的大小。组件的尺寸属性是布局中重点处理的属性,如果查看Flex帮助,你会看到关于Flex组件尺寸的属性有很多,以宽度为例,有以下相关的属性:

width

maxWidth

minWidth

explicitWidth

explicitMaxWidth

explicitMinWidth

measuredWidth

measuredMinWidth

percentWidth

scaleX

以及组件的MXML标记中的width属性

width:组件的当前实际宽度,以像素为单位。为什么会有当前实际宽度这样的说法呢?因为在Flex中可以为组件设置相对宽度,即百分比的表示宽度,这时组件当前的实际宽度是根据父容器的宽度动态计算出来的,开发者在设计界面时无法知道实际宽度,所以通过读取width属性可以知道其当前实际宽度。

measuredWidth:组件的默认宽度,以像素为单位。前面我们讲过,如果没显示指定组件的宽度(explicitWidth)或者设定组件的百分比宽度(percentWidth),那么组件需要自己提供默认宽度,否则无法显示组件。由于组件是通过measure()方法来获取组件的默认宽度,所以默认宽度属性就定义为measuredWidth。

explicitWidth:显式指定的宽度,以像素为单位。所谓显式指定宽度主要区别于动态的相对宽度,即区别于百分比宽度percentWidth。开发者设置该属性值时就已经知道到组件在运行时的宽度,故称为显式指定的宽度。该属性同百分比宽度互斥,一旦设置了explicitWidth属性,则percentWidth属性值就会变为NaN。同理,一旦设置了percentWidth,explicitWidth属性值就会变为NaN。如果用ActionsSript代码设置了组件的 width属性值,explicitWidth属性就会立即被赋予同样的值,同时percentWidth属性值会变为NaN。设置explicitWidth属性时,percentWidth属性值会立即被设置为NaN,但是width属性值不会立即改变,要延迟组件布局的commit阶段才会变为与 explicitWidth相同的值。

percentWidth:指组件的百分比宽度,比如设置组件占用父容器50%的宽度,那么就设置该属性值为50。该属性同显式指定的宽度(explicitWidth)互斥,一旦设置该属性值,则explicitWidth属性值立即变为NaN。

scaleX:当前组件宽度的缩放比例。一旦设置属性,考虑到性能,不会立即更新组件的width和explicitWidth属性,延迟到explicitWidth时会将width和explicitWidth属性值改变。

除了以上基本属性之外,值得注意的就是组件MXML标记中的width属性。这个属性在编译组件MXML标记时,由编译器根据标记中该属性值的格式编译成设置percentWidth或width属性的ActionScript代码。如果组件MXML标记的width属性后面有百分号,则其被编译为设置percentWidth属性的ActionScript代码。如果组件MXML标记的width后面不带百分号,则其被编译为设置width属性的ActionScript代码。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值