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...