2008年3月31日 星期一

Flex Image, SWFLoader Align Bug   [+/-]

Ticore's Blog

Flex Image, SWFLoader 组件置中对齐 Bug

Flex SDK Version:2.01, 3.0

发生条件:

Image or SWFLoader 的 scaleContent 设为 false
horizontalAlign 设为 center
verticalAlign 设为 middle
必须要指定 width, height
当内容物的大小超过指定的 width, height 时
Image or SWFLoader 画面排版就会错乱

Flex Image Align Bug Demo Code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   layout="horizontal" backgroundColor="#E0E0E0">
 <mx:HBox width="100%" height="100%" borderStyle="inset">
  <mx:Image source="@Embed(source='../assets/img.jpg')"
    scaleContent="false" alpha="0.7" width="100%" height="100%"
    horizontalAlign="center" verticalAlign="middle"/>
 </mx:HBox>
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

Flex Image Align Bug Screen Capture:

Read more...

2008年3月29日 星期六

ActionScript 多行程序码注解小技巧   [+/-]

Ticore's Blog

关于程序码注解,有分单行与多行注解 (文档上都有写)
多行注解有一个小技巧,可以比较快速的打开或是关闭整个区块的程序码

如下所示,这样是多行注解的

package {
 import flash.display.*;
 import flash.text.*;
 public dynamic class Main extends MovieClip {
  public function Main():void {
   
   /*/
   this.graphics.beginFill(0x808080, 0.5);
   this.graphics.drawRect(100, 50, 100, 100);
   this.graphics.endFill();
   //*/
   
  }
 }
}

只要加上一个斜线,就可以打开整块多行注解

package {
 import flash.display.*;
 import flash.text.*;
 public dynamic class Main extends MovieClip {
  public function Main():void {
   
   //*/
   this.graphics.beginFill(0x808080, 0.5);
   this.graphics.drawRect(100, 50, 100, 100);
   this.graphics.endFill();
   //*/
   
  }
 }
}

以上也是看来的技巧

以下分享一下变化型,可以很简单的在两个区块程序码做切换

下面的程序码有分 Block 1, 2
这样是打开 Block 1,关闭 Block 2
(虽然 dp.SyntaxHighlighter 标记颜色不是很正确)

package {
 import flash.display.*;
 import flash.text.*;
 public dynamic class Main extends MovieClip {
  public function Main():void {
   
   //*/
   // Block 1
   this.graphics.beginFill(0x808080, 0.5);
   this.graphics.drawRect(100, 50, 100, 100);
   this.graphics.endFill();
   /*/
   // Block 2
   var txt:TextField = new TextField();
   txt.x = 50;
   txt.y = 70;
   txt.width = 200;
   txt.height = 40;
   txt.border = true;
   txt.text = "Ticore's Blog \n http://ticore.blogspot.com";
   this.addChild(txt);
   //*/
   
  }
 }
}

只要拿掉一个斜线,就会变成
关闭 Block 1,打开 Block 2
很方便吧!

package {
 import flash.display.*;
 import flash.text.*;
 public dynamic class Main extends MovieClip {
  public function Main():void {
   
   /*/
   // Block 1
   this.graphics.beginFill(0x808080, 0.5);
   this.graphics.drawRect(100, 50, 100, 100);
   this.graphics.endFill();
   /*/
   // Block 2
   var txt:TextField = new TextField();
   txt.x = 50;
   txt.y = 70;
   txt.width = 200;
   txt.height = 40;
   txt.border = true;
   txt.text = "Ticore's Blog \n http://ticore.blogspot.com";
   this.addChild(txt);
   //*/
   
  }
 }
}

以上方式,应该可以适用于大部份采用 /*....*/ 多行注解的程序语言

Read more...

2008年3月25日 星期二

Flex ListBase selectedIndices, selectedItems Bug   [+/-]

Ticore's Blog

Flex ListBase, AdvancedListBase 有一个很严重的 Bug
只要是继承 ListBase, AdvancedListBase 的组件都会受到影响
像是 List, Menu, Tree, DataGrid, HorizontalList, TileList
与 AdvancedDataGrid, OLAPDataGrid

selectedIndices, selectedItems Bug 描述:

  • 当 dataProvider 内没有资料时,指定 selectedIndices 为空数组 []
    会造成往后取用 selectedIndices 永远得到空数组

  • 当 dataProvider 内没有资料时,指定 selectedItems 为空数组 []
    会造成往后取用 selectedItems 永远得到空数组

以上的 Bug 在 Flex SDK 2.0.1, 3.0 都会发生

ListBase selectedIndices, selectedItems Bug Demo Code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" fontSize="12"
  layout="vertical" verticalAlign="middle" backgroundColor="#F0F0F0">
 <mx:Style>
  Button {
   fontWeight: normal;
  }
 </mx:Style>
 <mx:Script>
  <![CDATA[
   import mx.collections.ArrayCollection;
   import mx.utils.ObjectUtil;
   
   [Bindable]
   public var itemData:ArrayCollection = new ArrayCollection();
   
   public function addItems():void{
    var num:Number = Math.random() * 20 + 3;
    for (var i:Number = 0 ; i < num ; i ++) {
     itemData.addItem({label: i});
    }
   }
   
   public function removeAllItems():void{
    itemData.removeAll();
   }
  ]]>
 </mx:Script>
 <mx:HBox>
  <mx:Label text="list.selectedIndices.length : {list.selectedIndices.length}" />
  <mx:Label text="list.selectedItems.length : {list.selectedItems.length}" />
 </mx:HBox>
 <mx:HRule width="100%" />
 <mx:HBox>
  <mx:List id="list" width="100" dataProvider="{itemData}" />
  <mx:VRule height="100%" />
  <mx:VBox>
   <mx:Button label="Add Items" click="addItems()" />
   <mx:Button label="Remove All  Items" click="removeAllItems()" />
   <mx:HRule width="100%"/>
   <mx:Button label="selectedIndices = []" click="list.selectedIndices = []" />
   <mx:Button label="selectedItems = []" click="list.selectedItems = []" />
   <mx:HRule width="100%"/>
   <mx:Button label="selectedIndex = -1" click="list.selectedIndex = -1" />
   <mx:Button label="selectedItem = null" click="list.selectedItem = null" />
  </mx:VBox>
  <mx:VRule height="100%" />
  <mx:VBox>
   <mx:Button label="trace(list.selectedIndices);"
     click="trace(ObjectUtil.toString(list.selectedIndices));" />
   <mx:Button label="trace(list.selectedItems);"
     click="trace(ObjectUtil.toString(list.selectedItems));" />
   <mx:Button label="trace(list.selectedIndex);"
     click="trace(list.selectedIndex);" />
  </mx:VBox>
 </mx:HBox>
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

只要在 List 没有资料情况下,点一下 "selectedIndices = []", selectedItems = []" 按钮
之后再按 "Add Items" 添加资料,点选 List 内的 Item
就会发现 selectedIndices, selectedItems 长度永远是 0
无法撤消

追踪 ListBase 原始码
发现问题是出在 bSelectedIndicesChanged, bSelectedItemsChanged
ListBase 内唯一将这两个变量设回 false 动作是发生在 adjustSelectionSettings 函式内

...
if (bSelectedIndicesChanged
    && (collectionHasItems || (_selectedIndices == null)))
{
    bSelectedIndicesChanged = false;
    bSelectedIndexChanged = false;
    commitSelectedIndices(_selectedIndices);
}

if (bSelectedItemsChanged
    && (collectionHasItems || (_selectedItems == null)))
{
    bSelectedItemsChanged = false;
    bSelectedIndexChanged = false;
    commitSelectedItems(_selectedItems);
}
...

但是 _selectedItems 根本不可能为 null
导致这两个旗标没有办法正常的被设回 false....

解决方式,只好自行继承 List 等相关组件
于设置 selectedIndices, selectedItems 时检查了

package com.ticore.uicomponents {
 import mx.controls.List;

 public class MyList extends List {
  public function MyList() {
   super();
  }
  
  [Bindable("change")]
  [Bindable("valueCommit")]
  [Inspectable(category="General")]
  public override function get selectedIndices():Array {
   return super.selectedIndices;
  }
  public override function set selectedIndices(indices:Array):void{
   if (this.collection && this.collection.length > 0) {
    super.selectedIndices = indices;
   }
  }
   
  [Bindable("change")]
  [Bindable("valueCommit")]
  [Inspectable(environment="none")]
  public override function get selectedItems():Array {
   return super.selectedItems;
  }
  public override function set selectedItems(items:Array):void{
   if (this.collection && this.collection.length > 0) {
    super.selectedItems = items;
   }
  }
   
 }
}

相关连结:
Flex ListBase selectedItems, selectedIndices 陷阱

Read more...

2008年3月22日 星期六

AS 3.0 - Mouse Event & mouseEnabled   [+/-]

Ticore's Blog

ActionScript 3.0 的事件机制有很大的改变
其中鼠标相关的事件也是
对于一个 InteractiveObject (MovieClip, Sprite, ...) 而言
"鼠标经过", "鼠标离开"表示两种状态

除了使用者移动鼠标之外
也可以透过控制对象的属性将"鼠标经过"状态改变为"鼠标离开"状态
eg. mouseEnabled, mouseChildren, hitArea, visible, removeClild, x, y

鼠标状态的改变,就会生成相关的鼠标事件
mouseOver, mouseOut
rollOver, rollOut
这些事件都会成对的发生
这一点与 ActionScript 2.0 有很大的不同

在 AS 2.0 一旦将 MovieClip.enabled 设为 false
就不会再收到 onRollOut 等事件
可是在 AS 3.0 在"鼠标经过"状态下,将对象 mouseEnabled 设为 false
意味着该对象与鼠标隔绝,变成为"鼠标离开"状态
所以会再丢出最后一个 mouseOut, rollOut 鼠标事件

或许不想要收到最后的那一个鼠标事件
只要在事件处理函式中检查 event.target 的 mouseEnabled 属性即可
不需要调用 removeEventListener 移除事件处理函式

假如常常用到,每次都要自行检查也挺麻烦的
以下介绍一个方式,可以让 mouseOut, rollOut 鼠标事件像 AS 2.0 行为一样
能够用 mouseEnabled 立即被停止

在 Mouse Event 捕捉阶段,通过 Stage 时
就拦截检查 target 的 mouseEnabled 属性...

/*
 Ticore's Blog
 http://ticore.blogspot.com/
*/
package {
 
 import flash.events.*;
 import flash.display.*;

 public class Main extends MovieClip {
  
  public var mc:MovieClip;
  
  public function Main() {
   
   createMC();
   
   stage.addEventListener(MouseEvent.MOUSE_OVER, onStageMouseHandler, true);
   stage.addEventListener(MouseEvent.MOUSE_OUT, onStageMouseHandler, true);
   stage.addEventListener(MouseEvent.ROLL_OVER, onStageMouseHandler, true);
   stage.addEventListener(MouseEvent.ROLL_OUT, onStageMouseHandler, true);
   
   mc.addEventListener(MouseEvent.CLICK, onMcClick);
   mc.addEventListener(MouseEvent.MOUSE_DOWN, onMouseEvent);
   mc.addEventListener(MouseEvent.MOUSE_UP, onMouseEvent);
   mc.addEventListener(MouseEvent.MOUSE_OVER, onMouseEvent);
   mc.addEventListener(MouseEvent.MOUSE_OUT, onMouseEvent);
   mc.addEventListener(MouseEvent.ROLL_OVER, onMouseEvent);
   mc.addEventListener(MouseEvent.ROLL_OUT, onMouseEvent);
  }
  
  public function createMC() {
   mc = new MovieClip();
   with (mc.graphics) {
    beginFill(0x000000, 0.6);
    drawRect(0, 0, 100, 100);
    endFill();
   }
   mc.x = 100;
   mc.y = 50;
   this.addChild(mc);
  }


  public function onMcClick(evtObj:MouseEvent):void{
   trace(evtObj.type);
   mc.visible = false;
   mc.mouseEnabled = false;
  }
  public function onMouseEvent(evtObj:MouseEvent):void{
   trace(evtObj.type);
  }
  
  
  public function onStageMouseHandler(evtObj:MouseEvent):void{
   var obj:InteractiveObject = evtObj.target as InteractiveObject;
   if (obj && !obj.mouseEnabled) {
    evtObj.stopImmediatePropagation();
   }
  }
 }
}

相关连结:
AS3 - MouseOver 与 RollOver 差异性 (1)
AS3 - MouseOver 与 RollOver 差异性 (2)
AS3 - MouseOver 与 RollOver 差异性 (3)

Read more...

2008年3月20日 星期四

Flex Tip - 在 Data Binding 内使用 [...] 运算子   [+/-]

Ticore's Blog

Flex MXML 的 Data Binding 功能很好用
但是在 Expression 区块内使用关联数组访问运算子会出现警告

Data binding will not be able to detect changes when using square bracket operator.
For Array, please use ArrayCollection.getItemAt() instead.

这是由于 Data Binding 无法检测到 Array 内元素的改变而跳出的警告消息
依照它的建议,改用 ArrayCollection.getItemAt() 可以解决
但是,很多情况下,资料来源并不是数组啊

以下便是一个例子
资料来源是 ObjectProxy 对象
objectProxy 对象整个被替换时,与 cb.value 改变时
Data Binding 都会被正常触发
objectProxy.prop1 属性单独改变时则不会触发
有时候,我们只需要这样的功能
但是它仍然会出现警告消息

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#F0F0F0" layout="vertical">
    <mx:Script>
        <![CDATA[
         import mx.utils.ObjectProxy;
         import mx.controls.*;
   
         [Bindable]
         public var objectProxy:ObjectProxy =
           new ObjectProxy({prop1: "Prop 1", prop2: "Prop 2", prop3: "Prop 3"});
        ]]>
    </mx:Script>
 <mx:ComboBox id="cb" dataProvider="[1, 2, 3]" />
 <mx:Label text="{objectProxy['prop' + cb.value]}" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

这个时候,就面临两难了
是要放弃好用的 Data Binding Expression? 或是对警告消息视而无见?

解决方式 1. 利用匿名函式将关联数组访问运算子包起来

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#F0F0F0" layout="vertical">
    <mx:Script>
        <![CDATA[
         import mx.utils.ObjectProxy;
         import mx.controls.*;
   
         [Bindable]
         public var objectProxy:ObjectProxy =
           new ObjectProxy({prop1: "Prop 1", prop2: "Prop 2", prop3: "Prop 3"});
        ]]>
    </mx:Script>
 <mx:ComboBox id="cb" dataProvider="[1, 2, 3]" />
 <mx:Label text="{(function():*{return objectProxy['prop' + cb.value];})(objectProxy, cb.value)}" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

解决方式 2. 将关联数组访问运算子放到外部函式

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#F0F0F0" layout="vertical">
    <mx:Script>
        <![CDATA[
         import mx.utils.ObjectProxy;
         import mx.controls.*;
   
         [Bindable]
         public var objectProxy:ObjectProxy =
           new ObjectProxy({prop1: "Prop 1", prop2: "Prop 2", prop3: "Prop 3"});
         
         public function getProp(...args):*{
          return objectProxy['prop' + cb.value];
         }
        ]]>
    </mx:Script>
 <mx:ComboBox id="cb" dataProvider="[1, 2, 3]" />
 <mx:Label text="{getProp(objectProxy, cb.value)}" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

重点来了,以上两种方法都有一个共通的要点
那就是 objectProxy, cb.value 这两个属性都要在 Data Binding Expression 内曝光一下
这样 Data Binding 才会抓到资料改变的触发事件

相关连结:
Flex 技巧 - 将资料绑定封装起来
Flex - 纯手工设置 DataBinding 的方式
Flex 技巧 - BindingManager 使用方式
Flex 技巧 - 观察 Data Binding 资料变化
Flex 2 Bindable Metadata Tag 背后实际作用
Flex 2.0 - 以 ActionScript 3.0 动态设置 Data Binding

Read more...

Flex 小技巧 - 让 List.selectedIndex 默认值为 0   [+/-]

Ticore's Blog

在使用 Flex List 或是其它具有 selectIndex 的组件时
常常会需要让 List 默认自动选到第一个 Item

不过当 List.dataProvider 资料来源变更时
之前设置好的 selectedIndex 又会被清除掉
假如企图在资料来源变更事件中主动设置 List.selectedIndex 也是没有作用的
因为 List 需要一点时间套用新的资料
这个时间差并不好抓
使用 callLater 也无法保证 100% 一定可行

以下分享一个小技巧
可以让 List 每次资料变更后,就自动默认选定第一个 Item 上

使用方式很简单,让 selectedIndex 自己绑定自己就好了

Flex MXML Code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#F0F0F0" layout="vertical">
    <mx:Script>
        <![CDATA[
   import mx.controls.*;
   
   [Bindable]
   public var listData:Array = [];
   
   public function doUpdateData():void{
    listData = [];
    for (var i:Number = 0 ; i < 16 ; ++i) {
     listData.push(Math.round(Math.random() * 10000));
    }
   }
        ]]>
    </mx:Script>
 <mx:List id="list" width="100" height="200" dataProvider="{listData}"
   selectedIndex="{list.selectedIndex &lt; 0 ? 0 : list.selectedIndex}" />
 <mx:Button label="Update Data" click="doUpdateData()" />
</mx:Application>
<!-- Ticore's BLog - http://ticore.blogspot.com/ -->
Read more...

2008年3月19日 星期三

Flex Button with Constraint Layout   [+/-]

Ticore's Blog

利用 Flex 3 新的排版对齐功能 - ConstraintColumn, ConstraintRow
配合 Data Binding 与 Slider 动态控制 Button 排版

Flex MXML Code:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  backgroundColor="#DDDDDD" layout="horizontal">
 
 <mx:Canvas width="100%" height="100%">
  <mx:Canvas top="0" left="0" right="50" bottom="50" borderStyle="inset">
   <mx:constraintColumns>
    <mx:ConstraintColumn id="col1" percentWidth="{sliderH.values.slice(0, 1).pop()}" />
    <mx:ConstraintColumn id="col2" percentWidth="{sliderH.values.slice(1, 2).pop() - sliderH.values.slice(0, 1).pop()}" />
    <mx:ConstraintColumn id="col3" percentWidth="{100 - sliderH.values.slice(1, 2).pop()}" />
   </mx:constraintColumns>
   <mx:constraintRows>
    <mx:ConstraintRow id="row1" percentHeight="{100 - sliderV.values.slice(1, 2).pop()}" />
    <mx:ConstraintRow id="row2" percentHeight="{sliderV.values.slice(1, 2).pop() - sliderV.values.slice(0, 1).pop()}" />
    <mx:ConstraintRow id="row3" percentHeight="{sliderV.values.slice(0, 1).pop()}" />
   </mx:constraintRows>
   <mx:Button label="Button" minWidth="1" minHeight="1"
    left="col2:0" right="col2:0" top="row2:0" bottom="row2:0" />
  </mx:Canvas>
  
  <mx:HSlider id="sliderH" minWidth="10" left="0" bottom="0" right="50" minimum="0" tickInterval="10"
    maximum="100" thumbCount="2" values="[30, 70]" labels="[0, 50, 100]" liveDragging="true" />
  
  <mx:VSlider id="sliderV" minHeight="10" top="0" right="0" bottom="50" minimum="0" tickInterval="10"
    maximum="100" thumbCount="2" values="[30, 70]" labels="[0, 50, 100]" liveDragging="true" />
  
 </mx:Canvas>
 
</mx:Application>
<!-- Ticore's BLog - http://ticore.blogspot.com/ -->

相关连结:
Flex - Daily Task View by Constraint Layout

Read more...

2008年3月11日 星期二

Flash ActionScript 2 Pre-Compiler Bug   [+/-]

Ticore's Blog

从 MXNA 看到一篇有趣的文章
Why SOMETIMES … (String == Number) ….
在 ActionScript 直接比较意义相同的数值与字串
居然有的会得到 ture,有的会得到 false
真是诡异

于是也来测试看看
ActionScript 2.0 测试程序

trace('0.90' == 0.90); // true
trace('0.91' == 0.91); // true
trace('0.92' == 0.92); // true
trace('0.93' == 0.93); // true
trace('0.94' == 0.94); // false
trace('0.95' == 0.95); // false
trace('0.96' == 0.96); // true
trace('0.97' == 0.97); // true
trace('0.98' == 0.98); // true
trace('0.99' == 0.99); // true

后来想到用 AS Decompiler 去看看
结果如下:

    trace(true);
    trace(true);
    trace(true);
    trace(true);
    trace(false);
    trace(false);
    trace(true);
    trace(true);
    trace(true);
    trace(true);

原来是 Flash IDE Pre-Compiler (前处理器) 的 Bug
实际用 ActionScript 比较的结果还是正确的

Read more...

Adobe AIR Live Documents   [+/-]

Ticore's Blog

Adobe AIR 线上文档下载

Adobe AIR Flash LiveDocs
Adobe AIR HTML and Ajax LiveDocs

Read more...

2008年3月10日 星期一

Flex - 简单实作 No Border Image   [+/-]

Ticore's Blog

Flex Image 组件缺少像 Flash Movie 那样 No Boder 的对齐方式
可以 100% 填充指定范围,又可以维持长宽比例

假如把 maintainAspectRatio 设为 false
勉强可以达到 100% 填充指定尺寸
但是也会导致图片变形,并不实用

假如要自行更改 Image,可能需要看不少程序码
以下示范一种比较简单的方式
不需要去了解 Flex Image UIComponent 内部运作
仅使用一个 Canvas 嵌套 Image,加上几行程序
就可以达到 No Boder 对齐方式

NoBorderImage MXML:

<?xml version="1.0" encoding="utf-8"?>
<!-- Ticore's BLog - http://ticore.blogspot.com/ -->
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%"
   verticalScrollPolicy="off" horizontalScrollPolicy="off" resize="resetInner()">
 <mx:Script>
  <![CDATA[
   [Bindable]
   public var source:String;
   private function resetInner():void{
    var ratioFlag:Boolean = (width / height) > (img.contentWidth / img.contentHeight);
    img.width = ratioFlag ? width : height * (img.contentWidth / img.contentHeight);
    img.height = !ratioFlag ? height : width * (img.contentHeight / img.contentWidth);
   }
  ]]>
 </mx:Script>
 <mx:Image id="img" source="{source}" init="resetInner()"
   verticalCenter="0" horizontalCenter="0" verticalAlign="middle" horizontalAlign="center" />
</mx:Canvas>

NoBorderImage 使用示范:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application layout="vertical" backgroundColor="#E0E0E0" verticalGap="0"
   xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:comp="com.ticore.uicomponents.*">
 
 <mx:Label text="No Border Image" fontSize="16" fontWeight="bold" />
 
 <comp:NoBorderImage source="@Embed('img.jpg')" width="100%" height="100%" />
 
 <mx:Label>
  <mx:htmlText>
   <![CDATA[<a href='http://ticore.blogspot.com/' target='_blank'>Ticore's Blog]]>
   <![CDATA[ - http://ticore.blogspot.com/</a>]]>
  </mx:htmlText>
 </mx:Label>
</mx:Application>

点击这里看线上示范

相关连结:
Flash AS3 No Border Scale Background Image

Read more...

AS 技巧 - 强迫更新 DisplayObject.scrollRect 尺寸   [+/-]

Ticore's Blog

AS 技巧 - 强迫 DisplayObject.scrollRect 更新尺寸

上一篇提到 DisplayObject.scrollRect 特性
更改过 scrollRect 之后,需要一点时间,才会影响到对象的尺寸

另外,假如该 DisplayObject 对象没有放置在 Stage 之下
scrollRect 就不会影响到对象的尺寸
这就更诡异了

以上两种诡异特性
对于需要做对象缩放排版的功能时,很容易生成潜在的 Bug
尤其是需要开发或是更改 Flex UI Component 时

就算知道了,对于需要时间反映在对象尺寸特性
还是很难避免
难道每次更改过 scrollRect 之后,都要使用 setTimeout or callLater 吗?

以下分享一个小技巧
可以让你在变动过 scrollRect 之后,立即强迫 DisplayObject 更新尺寸相关属性

AS3 示范程序:

/*
 Ticore's Blog
 http://ticore.blogspot.com
*/

package {
 import flash.display.*;
 import flash.geom.*;
 import flash.utils.*;
 
 public class Main extends MovieClip {
  
  var mc:MovieClip;
  
  public function Main() {
   doTest();
  }

  public function doTest() {
   mc = new MovieClip();
   this.addChild(mc);
   
   var g:Graphics = mc.graphics;
   g.beginFill(0xFF0000);
   g.drawRect(0, 0, 100, 100);
   g.endFill();
   traceSize("After draw rectangle graphic", mc);

   mc.scrollRect = new Rectangle(0, 0, 50, 50);
   traceSize("After assign scrollRect", mc);
   
   //*/
   // Force DisplayObject update dimensions
   var bmpData:BitmapData = new BitmapData(1, 1);
   bmpData.draw(mc);
   traceSize("After draw by BitmapData", mc);
   //*/
   
   setTimeout(traceSize, 0, "0 ms later", mc);
   setTimeout(traceSize, 10, "10 ms later", mc);
   setTimeout(traceSize, 500, "500 ms later", mc);
  }
  
  public function traceSize(msg:String, target:DisplayObject):void{
   trace("----------------------------------------------------");
   trace(msg, ", time:" + getTimer());
   trace("width:", mc.width, ", height:", mc.height,
      ", bounds:", mc.getBounds(mc.parent));
  }
  
 }
}

输出结果:

----------------------------------------------------
After draw rectangle graphic , time:7
width: 100 , height: 100 , bounds: (x=0, y=0, w=100, h=100)
----------------------------------------------------
After assign scrollRect , time:13
width: 100 , height: 100 , bounds: (x=0, y=0, w=100, h=100)
----------------------------------------------------
After draw by BitmapData , time:45
width: 50 , height: 50 , bounds: (x=0, y=0, w=50, h=50)
----------------------------------------------------
0 ms later , time:85
width: 50 , height: 50 , bounds: (x=0, y=0, w=50, h=50)
----------------------------------------------------
10 ms later , time:92
width: 50 , height: 50 , bounds: (x=0, y=0, w=50, h=50)
----------------------------------------------------
500 ms later , time:571
width: 50 , height: 50 , bounds: (x=0, y=0, w=50, h=50)

相关连结:
AS - scrollRect 与 Mask 差异
What you should know about DisplayObject’s mask and scrollRect

Read more...

2008年3月9日 星期日

AS - scrollRect 与 Mask 差异   [+/-]

Ticore's Blog

自从 Flash 8 开始添加了 scrollRect 功能
让开发者可以指定一块矩形区域限制表现的范围
功能上有点类似 Mask,程序写起来也比 Mask 简单一些
几乎所有需要卷轴区块的组件都是用 scrollRect 实作的

很明显的一个差异是,Mask 可以做任何形状的遮罩,scrollRect 只能用矩形

另外,还有一个特性是比较不为人知的
Mask 并不会影响到 DisplayObject 对象的 width, height, bounds 等尺寸属性
可是 scrollRect 会影响到 DisplayObject 对象的尺寸

以下分别用 Mask 与 scrollRect 做测试
以 ActionScript 创建 100*100 大小的 MovieClip
套用 50*50 的 Mask or scrollRect

AS3 DisplayObject with Mask:

package {
 import flash.display.*;
 import flash.geom.*;
 import flash.utils.*;
 
 public class Main  extends MovieClip {
  
  var mc:MovieClip;
  var maskMC:MovieClip;
  
  public function Main() {
   doTest();
  }

  public function doTest() {
   mc = new MovieClip();
   mc.cacheAsBitmap = true;
   maskMC = new MovieClip();
   this.addChild(mc);
   mc.addChild(maskMC);
   
   mc.mask = maskMC;
   
   var g:Graphics = mc.graphics;
   
   g.beginFill(0xFF0000);
   g.drawRect(0, 0, 100, 100);
   g.endFill();
   
   g = maskMC.graphics;
   g.beginFill(0xFF0000);
   g.drawRect(0, 0, 50, 50);
   g.endFill();
   
   setTimeout(traceSize, 500, mc);
  }
  
  public function traceSize(target:DisplayObject):void{
   trace("time:" + getTimer());
   trace("width:", mc.width, ", height:", mc.height,
      ", bounds:", mc.getBounds(mc.parent));
  }
  
 }
}

//  Ticore's Blog http://ticore.blogspot.com/

输出结果:

time:553
width: 100 , height: 100 , bounds: (x=0, y=0, w=100, h=100)

AS3 DisplayObject with scrollRect:

package {
 import flash.display.*;
 import flash.geom.*;
 import flash.utils.*;
 
 public class Main  extends MovieClip {
  
  var mc:MovieClip;
  
  public function Main() {
   doTest();
  }

  public function doTest() {
   mc = new MovieClip();
   this.addChild(mc);
   
   var g:Graphics = mc.graphics;
   g.beginFill(0xFF0000);
   g.drawRect(0, 0, 100, 100);
   g.endFill();

   mc.scrollRect = new Rectangle(0, 0, 50, 50);
   
   setTimeout(traceSize, 500, mc);
  }
  
  public function traceSize(target:DisplayObject):void{
   trace("time:" + getTimer());
   trace("width:", mc.width, ", height:", mc.height,
      ", bounds:", mc.getBounds(mc.parent));
  }
  
 }
}

//  Ticore's Blog http://ticore.blogspot.com/

输出结果:

time:535
width: 50 , height: 50 , bounds: (x=0, y=0, w=50, h=50)

由输出结果可以看出,Mask 对被遮罩对象尺寸没有影响
至于为什么要延迟一小段时间
这是因为被套用 scrollRect 之后,需要一点时间,才会对尺寸发生作用
真是诡异的特性

相关连结:
AS 技巧 - 强迫更新 DisplayObject.scrollRect 尺寸

Read more...

2008年3月2日 星期日

Flex MXML 多行 HTML 文字撰写技巧   [+/-]

Ticore's Blog

在开发 Flex MXML 时,偶尔会遇到需要放置 html 文字
有时候 html 文字会很长需要折行
有时候 < > & 等符号又需要写成 HTML Entity....
以下分享在 MXML 内使用 HTML 文字的经验

首先,直接在 Label 标签属性 text、htmlText 内折行都是 OK 的
Flex 编译器会自动将自动换行字符转换掉,变成单行文字
不过假如需要保留断行字符时,就不能这样用了
而且在标签属性中,htmlText 必须使用 HTML Entity,非常不方便

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  fontSize="12" backgroundColor="#E0E0E0">
 <mx:Label text="Ticore's Blog - 
  http://ticore.blogspot.com/" />
</mx:Application>
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  fontSize="12" backgroundColor="#E0E0E0">
 <mx:Label htmlText="Ticore's Blog - 
  &lt;a href='http://ticore.blogspot.com/'&gt;
  http://ticore.blogspot.com/&lt;/a&gt;" />
</mx:Application>

接下来改用独立的 htmlText 子节点,并且使用 CDATA 标记区块
这样就不用将特殊符号转成 HTML Entity

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  fontSize="12" backgroundColor="#E0E0E0">
 <mx:Label>
  <mx:htmlText>
   <![CDATA[Ticore's Blog - 
   <a href='http://ticore.blogspot.com/'>http://ticore.blogspot.com/</a>]]>
  </mx:htmlText>
 </mx:Label>
</mx:Application>

当内容太长,需要折行时
自动换行字符会被编译为 ActionScript 字串
可是 Label 组件并不能吃多行文字
结果如下图所示,在 Label 组件上只有显示第一行

假如改用多个 CDATA 区块

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  fontSize="12" backgroundColor="#E0E0E0">
 <mx:Label>
  <mx:htmlText>
   <![CDATA[Ticore's Blog - ]]>
   <![CDATA[<a href='http://ticore.blogspot.com/'>]]>
   <![CDATA[http://ticore.blogspot.com/</a>]]>
  </mx:htmlText>
 </mx:Label>
</mx:Application>

不用将特殊符号转成 HTML Entity
程序码撰写上可以使用折行
也可以自由选择是否保留自动换行字符
两全其美的方法

有点类似撰写程序处理长字串折行方式

var longStr = "0123456";
longStr += "0123456";
longStr += "0123456";
longStr += "0123456";
Read more...