2008年6月27日 星期五

Flex 技巧 - 將資料綁定封裝起來   [+/-]

Ticore's Blog

之前介紹了 純手工設定 Flex DataBinding 的方式
不過那挺麻煩的
假如想要將 DataBinding 封裝起來,保留部分彈性
又不想要那麼麻煩的設定方式
不妨可以試試看以下的方式

在這個例子中,完全的將 DataBinding 封裝在一個 MXML Component 中
必須要指定好目標物,Component 內的 DataBinding 才會發生作用
想要停止 DataBinding 也很簡單,只要將目標屬性設為 null 就好

甚至可以對一份資料,準備多個 DataBinding Component
只要在執行期動態替換 Component,就能達到切換 DataBinding 行為的目的
其實還挺方便的

Main.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  verticalAlign="middle" backgroundColor="#FFFFFF"
  creationComplete="init();" fontSize="12">
 <mx:Script>
  <![CDATA[
   public var comp:BindingComp;
   
   public function init():void{
    comp = new BindingComp();
    comp.initialize();
   }
  ]]>
 </mx:Script>
 <mx:HBox>
  <mx:Label text="No 1:" />
  <mx:NumericStepper id="no1" maximum="100" />
 </mx:HBox>
 <mx:HBox>
  <mx:Label text="No 2:" />
  <mx:NumericStepper id="no2" maximum="100" />
 </mx:HBox>
 <mx:CheckBox id="chk" label="DataBinding Enabled"
   change="comp.target = chk.selected ? this : null;" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

BindingComp.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:UIComponent xmlns:mx="http://www.adobe.com/2006/mxml">
 <mx:Script>
  <![CDATA[
   [Bindable]
   public var target:Main;
   
   public function doBinding1(... args:*):void{
    if (target) target.no2.value = target.no1.value;
   }
   public function doBinding2(... args:*):void{
    if (target) target.no1.value = target.no2.value;
   }
  ]]>
 </mx:Script>
 <mx:Model>
  {doBinding1(target.no1.value)}
 </mx:Model>
 <mx:Model>
  {doBinding2(target.no2.value)}
 </mx:Model>
</mx:UIComponent>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

線上測試範例:

相關連結:
Flex 4 Gumbo 雙向資料繫結測試
Flex - 純手工設定 DataBinding 的方式
Flex 技巧 - BindingManager 使用方式
Flex 技巧 - 觀察 Data Binding 資料變化
Flex Tip - 在 Data Binding 內使用 [...] 運算子
Flex 2 Bindable Metadata Tag 背後實際作用
Flex 2.0 - 以 ActionScript 3.0 動態設置 Data Binding

Read more...

2008年6月25日 星期三

關於 MMUG.TW 論壇暫停服務   [+/-]

Ticore's Blog

台灣 macromedia 使用者俱樂部論壇 因為一些說來話長的原因,暫停服務一陣子!

若是您在這段期間有什麼 Flash 的問題 "急著" 想要找人請教與討論的話
歡迎到 Google Group 平台的 AUG.TW 繼續發問:
http://groups.google.com/group/augtw

Read more...

2008年6月18日 星期三

Flex SDK 馬歇爾計畫   [+/-]

Ticore's Blog

Marshall Plan 原文有點長,主要只有兩件事情:

  • 不同版本交互支援 (Cross-Versioning):
    不同版本 Flex 編譯的 SWFs 可以被放在相同的 SecurityDomain 執行
    但是卻可以有不同的 ApplicationDomain

  • 不信任的應用程式支援 (Untrusted Application):
    被載入到不同 SecurityDomain 的 SWFs 將不能存取主應用程式或是 Stage 與其它受限的資源

這個計畫將可能會在 Flex 3.1 開始支援
未來不同版本的 Flex 應用程式可以做混搭了
個人猜測,這計畫背後更重要的意義是 Flash 與 Flex 應用程式混搭

不過在那之前,Adobe 可能要先把 ApplicationDomain 的 Bug 處理掉吧~

相關連結:
Flex 4 Gumbo MXML 命名空間的問題

Read more...

2008年6月17日 星期二

Adobe AIR 1.1 出了   [+/-]

Ticore's Blog

Adobe AIR 1.1 出了,HTML Input Text 終於支援雙位元文字輸入法了

Download Adobe AIR SDK
Adobe AIR extension for Dreamweaver CS3
Installing Adobe Air 1.1 Update for Flash CS3 Professional

相關連結:
純程式建立 AIR AS3-JS 混搭的簡單範例
注意你的 AIR and Flash Player version
AIR - 如何區分 JavaScript 與 ActionScript 物件
AIR - ActionScript, JavaScript 混搭技巧

Read more...

2008年6月14日 星期六

AS 技巧 - Layer BlendMode 的用處   [+/-]

Ticore's Blog

Flash Player 8 新增的混合模式功能中的圖層模式 (Layer)
一般使用起來或許覺得沒有什麼特別的用處
說明文件上寫得更是令人霧茫茫
簡單的說,只是讓 DisplayObject 子物件預先混和顏色而已

基本上,除了 Normal 之外的混合模式,都會強迫預先混和子物件顏色
但是其它混合模式都是有特殊效果的
假如不需要那些效果,但是又要強迫預先混合顏色時
就要用 Layer 混合模式了

對於像是 Flex 這樣由大量的 DisplayObject 組合而成的組件
遇到需要淡入、淡出效果時
即使是在最外層設定 Alpha 透明度
每個子物件仍會先被單獨套用 Alpha 效果再疊合成一張圖
這樣就會有某些位置顏色特別突兀不透明

此時 Layer 混合模式就非常好用了
它可以讓整個表單先疊合成一張圖再進行 Alpha 效果
可以確保組件顏色看起來不會特別突兀

以下是用 Flex 作的簡單測試
可以容易觀察到多層巢狀組件在不同 Alpha, BlendMode 的效果

<?xml version="1.0"?>
<mx:Application layout="vertical" fontSize="12" backgroundColor="#FFFFFF"
   xmlns:mx="http://www.adobe.com/2006/mxml">
 <mx:Style>
  HBox.whiteBox {
   paddingTop: 15px;
   paddingBottom: 15px;
   paddingLeft: 15px;
   paddingRight: 15px;
   backgroundColor: #000000;
  }
 </mx:Style>
 <mx:HBox styleName="whiteBox" alpha="{alphaSlider.value}"
    blendMode="{blendModeCb.value ? blendModeCb.value : 'normal'}">
  <mx:HBox styleName="whiteBox">
   <mx:HBox styleName="whiteBox">
    <mx:HBox styleName="whiteBox" />
   </mx:HBox>
  </mx:HBox>
 </mx:HBox>
 
 <mx:HRule width="100%" />
 <mx:HBox verticalAlign="middle">
  <mx:Label text="BlendMode: " />
  <mx:ComboBox id="blendModeCb">
   <mx:dataProvider>
    ["normal", "layer", "darken", "invert", "hardlight"]
   </mx:dataProvider>
  </mx:ComboBox>
 </mx:HBox>
 <mx:HBox verticalAlign="middle">
  <mx:Label text="Alpha: " />
  <mx:HSlider id="alphaSlider" value="0.5"
    tickValues="[0, 0.5, 1]" labels="[0, 0.5, 1]"
    minimum="0" maximum="1" liveDragging="true" />
 </mx:HBox>
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

線上測示範例:

相關連結:
Flex Label, TextField 半透明小技巧
Flash 8 半透明輸入、動態文字欄位

Read more...

2008年6月10日 星期二

Flex - 純手工設定 DataBinding 的方式   [+/-]

Ticore's Blog

Flex 的 DataBinding Expression 功能雖然非常方便
不用自行呼叫 addEventListener,省去了不少程式碼
但是換個角度看,Flex DataBinding 其實是有點缺乏彈性
不用自行加入監聽事件,同時也意味著不能移除監聽事件

然而,自行利用 addEventListener 方式實作的 DataBinding
感覺好像又沒有 Flex Compiler 產生的好~
於是想要觀察 Flex Compiler 產生的程式碼
進而自行模仿實作 DataBinding

想要觀察 Flex Compiler 產生的 ActionScript 很簡單
只要加入編譯參數 -keep-generated-actionscript=true
就可以在 /src/generated 下找到了

舉例來說,想要模擬以下的 DataBinding Expression:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" layout="vertical" fontSize="12">
   
  <mx:Label text="Binding Source:" />
  <mx:HSlider id="slider1" snapInterval="1" maximum="100" value="50" />

  <mx:Label text="Binding Destination:" />
  <mx:HSlider id="slider2" snapInterval="1" maximum="100" value="{slider1.value}" />
  
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

步驟有點多~~

  1. 實作 mx.binding.IBindingClient; 介面

  2. 匯入必要的 Class:

    import mx.binding.*;
    import mx.binding.utils.*;
    import mx.core.mx_internal;
    

  3. 宣告 Bindings, Watchers 等屬性:

    mx_internal var _bindings : Array = [];
    mx_internal var _watchers : Array = [];
    mx_internal var _bindingsByDestination : Object = {};
    mx_internal var _bindingsBeginWithWord : Object = {};
    

  4. 建立 Bindings 與 Watchers:

    mx_internal::_bindings[0] = new Binding(this,
     function():* {return slider1.value;},
     function(sourceReturnValue:*):void {slider2.value = sourceReturnValue;},
     "slider2.value");
    
    mx_internal::_watchers[0] = new PropertyWatcher("slider1",
       {propertyChange: true},
       [mx_internal::_bindings[0]],
       function(propertyName:String):* { return this[propertyName]; });
    
    mx_internal::_watchers[1] = new PropertyWatcher("value",
       {valueCommit: true, change: true},
       [mx_internal::_bindings[0]], null);
    
    mx_internal::_watchers[0].updateParent(this);
    mx_internal::_watchers[0].addChild(mx_internal::_watchers[1]);
    
    mx_internal::_bindings[0].execute();
    

最後一個步驟看起來就有點複雜了
Binding 的功能有點類似 Event Handler,負責執行 DataBinding 運算
而 Watcher 則是類似 Event Listener,負責監聽資料來源的變化
為什麼不用標準的 Event Listener 機制
看 Flex Source 上寫的是因為效能考量

先看一下 mx.binding.Binding 類別的使用方式
public function Binding(document:Object, srcFunc:Function, destFunc:Function, destString:String)

  • document: binding 目標的文件
  • srcFunc: 用來取值的函式
  • destFunc: 將值指定到目的地的函式
  • destString: 用來告訴 ValidationManager 驗證該欄位

至於 Watcher 其實只是一個上層類別
實際使用時,需要視 Binding Source 種類決定使用哪一種子 Watcher
XMLWatcher, PropertyWatcher, StaticPropertyWatcher, RepeaterItemWatcher, RepeaterComponentWatcher, FunctionReturnWatcher, ArrayElementWatcher

Watcher 有一個最特別的地方是,它具有父子關係
上層的父 Watcher 會觸發下層的子 Watcher 物件
可以藉由以下 Watcher 函式設定:

public function updateParent(parent:Object):void;
public function addChild(child:Watcher):void;
public function removeChildren(startingIndex:int):void;
public function updateChildren():void;

綜合上述的步驟
完整手工設定的 DataBinding MXML 程式碼如下:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" layout="vertical" fontSize="12"
   implements="mx.binding.IBindingClient"
   creationComplete="onCreateComplete();">
  
  <mx:Script>
   <![CDATA[
    import mx.binding.*;
    import mx.binding.utils.*;
    import mx.core.mx_internal;
    
    mx_internal var _bindings : Array = [];
    mx_internal var _watchers : Array = [];
    mx_internal var _bindingsByDestination : Object = {};
    mx_internal var _bindingsBeginWithWord : Object = {};
    
    public function onCreateComplete():void{
     
     mx_internal::_bindings[0] = new Binding(this,
      function():* {return slider1.value;},
      function(sourceReturnValue:*):void {slider2.value = sourceReturnValue;},
      "slider2.value");
     
     // mx_internal::_bindings[0].mx_internal::isEnabled = false;
     
     mx_internal::_watchers[0] = new PropertyWatcher("slider1",
        {propertyChange: true},
        [mx_internal::_bindings[0]],
        function(propertyName:String):* { return this[propertyName]; });
     
     mx_internal::_watchers[1] = new PropertyWatcher("value",
        {valueCommit: true, change: true},
        [mx_internal::_bindings[0]], null);
     
     mx_internal::_watchers[0].updateParent(this);
     mx_internal::_watchers[0].addChild(mx_internal::_watchers[1]);
     
     mx_internal::_bindings[0].execute();
     
     // BindingManager.debugBinding("slider2.value");
    }
   ]]>
  </mx:Script>
  
  <mx:Label text="Binding Source:" />
  <mx:HSlider id="slider1" snapInterval="1" maximum="100" value="50" />

  <mx:Label text="Binding Destination:" />
  <mx:HSlider id="slider2" snapInterval="1" maximum="100" />
  
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

相關連結:
Flex 4 Gumbo 雙向資料繫結測試
Flex 技巧 - 將資料綁定封裝起來
Flex 技巧 - BindingManager 使用方式
Flex 技巧 - 觀察 Data Binding 資料變化
Flex Tip - 在 Data Binding 內使用 [...] 運算子
Flex 2 Bindable Metadata Tag 背後實際作用
Flex 2.0 - 以 ActionScript 3.0 動態設置 Data Binding
Soph-Ware Associates Blog - Data Binding in Flex, Part I
Soph-Ware Associates Blog - Data Binding in Flex, Part II

Read more...

2008年6月8日 星期日

Flex 技巧 - BindingManager 使用方式   [+/-]

Ticore's Blog

Flex 的 mx.binding.*; 內有許多未公開的類別
主要都是給 MXML Compiler 使用的
其中 mx.binding.BindingManager 便是負責管理所有的 DataBinding 運作
BindingManager 內有一些靜態函式還蠻有用的
列舉如下:

  • BindingManager.setEnabled(document:Object, isEnabled:Boolean):void;
    用來 停止/啟動 Flex Application/Component 內 Data Binding

  • BindingManager.executeBindings(document:Object, destStr:String, destObj:Object):void;
    執行被指定 Data Binding Expression

  • BindingManager.debugBinding(destinationString:String):void;
    對指定的 Data Binding Expression 進行除錯

以下是簡單的 BindingManager 使用示範程式:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" layout="vertical" fontSize="12"
   creationComplete="onCreateComplete();">
  <mx:Script>
   <![CDATA[
    import mx.binding.*;
    public function onCreateComplete():void{
     BindingManager.debugBinding("slider2.value");
    }
   ]]>
  </mx:Script>
  
  <mx:Label text="Binding Source:" />
  <mx:HSlider id="slider1" snapInterval="1" maximum="100" value="50" />

  <mx:Label text="Binding Destination:" />
  <mx:HSlider id="slider2" snapInterval="1" maximum="100" value="{slider1.value}" />
  
  <mx:CheckBox id="chk" label="Binding Enabled" selected="true"
    change="BindingManager.setEnabled(this, chk.selected); btn.enabled = chk.selected;" />
    
  <mx:Button id="btn" label="Execute DataBinding"
    click="BindingManager.executeBindings(this, 'slider2.value', null);" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

測試輸出結果:

Binding: destString = slider2.value, srcFunc result = 54
Binding: destString = slider2.value, srcFunc result = 59
Binding: destString = slider2.value, srcFunc result = 81
Binding: destString = slider2.value, srcFunc result = 41

相關連結:
Flex 4 Gumbo 雙向資料繫結測試
Flex 技巧 - 將資料綁定封裝起來
Flex - 純手工設定 DataBinding 的方式
Flex 技巧 - 觀察 Data Binding 資料變化
Flex Tip - 在 Data Binding 內使用 [...] 運算子
Flex 2 Bindable Metadata Tag 背後實際作用
Flex 2.0 - 以 ActionScript 3.0 動態設置 Data Binding

Read more...

2008年6月6日 星期五

Flex 技巧 - 觀察 Data Binding 資料變化   [+/-]

Ticore's Blog

Flex Data Binding 功能讓開發者不用寫太多的程式碼
就能做到資料繫結功能
但是要除錯的時候就比較不太方便
Data Binding Expression 區塊內很多語法都不能使用
當 Data Binding 被觸發時,想要觀察資料變化就不太方便

以下分享一個小技巧,可以很簡單的觀察 Data Binding 前後資料的變化

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" layout="vertical" fontSize="12">
  
  <mx:Label text="Binding Source:" />
  <mx:HSlider id="slider1" snapInterval="1" maximum="100" />

  <mx:Label text="Binding Destination:" />
  <mx:HSlider id="slider2" snapInterval="1" maximum="100"
    value="{trace('Before :', slider2.value),
    setTimeout(function():void{trace('After :', slider2.value);}, 0), slider1.value}"/>
  
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

由於 Data Binding Expression 內不能使用 ";" 結尾的陳述式
所以使用 "," 作區隔,只有最後一個 Expression 會被當作值指定給目標
這樣在前面就可以 trace 到變化之前的值
配合 setTimeout 又可以觀察到變化之後的值

相關連結:
Flex 4 Gumbo 雙向資料繫結測試
Flex 技巧 - 將資料綁定封裝起來
Flex - 純手工設定 DataBinding 的方式
Flex 技巧 - BindingManager 使用方式
Flex Tip - 在 Data Binding 內使用 [...] 運算子
Flex 2 Bindable Metadata Tag 背後實際作用
Flex 2.0 - 以 ActionScript 3.0 動態設置 Data Binding

Read more...

2008年6月3日 星期二

Flash 內嵌動態文字與樣式的問題   [+/-]

Ticore's Blog

問題出處:動態文字欄位的問題

問題描述:

於 Flash IDE 舞台上
放置兩個動態文字欄位,選擇相同的字體
第一個不嵌入任何字集,樣式設為 regular
第二個嵌入數字字元集,樣式設為 bold
於執行期動態重設第二個文字欄位內容
該文字欄位將無法表現新的文字內容

簡化過後的問題 Demo 程式如下:

注意,測試的時候不要先選取 txt2 內的文字
只要一選取過,就不過出現問題了

原始檔案下載

這個問題其實還挺複雜的,由許多的特性共同影響,分述如下~

Flash TextField 與 Embed Font 特性:

特性 1.
基本上,Flash 的內嵌字體,即使是相同的字體名稱
不同的樣式 (regular, bold, italic) 會被當作完全不同的字體處理

特性 2.
Flash SWF 內所有時間軸預置 TextField 內嵌字體都是可以共用的

依據特性 1. 2.,可以做一個簡單的測試
於 Flash IDE 舞台上放置兩個動態文字欄位
第一個文字欄位僅嵌入 Airal regular 數字字集
第二個文字欄位僅嵌入 Airal bold 英文字母字集
動態將第二個文字欄位樣式設為 regular 之後
那麼該文字欄位只能表現數字了~~

特性 3.
一個 SWF 內僅嵌入單一字體樣式 (e.g. Arial regular) 時
動態使用同一字體但是不同樣式 (e.g. Arial bold) 的文字欄位
將會使用該字體唯一嵌入樣式 (e.g. Arial regular) 作為替代字體

特性 4.
將 TextField.text 內容重設時
TextField 內的文字樣式 bold, italic 也會被重設為預設的樣式
AS3 TextField.appendText 則不會重設樣式

ActionScript 3.0 測試程式:

package {
 import flash.display.*;
 import flash.text.*;

 public class Main1 extends MovieClip {

  public function Main1() {

   var txt:TextField = new TextField();
   var tf:TextFormat = new TextFormat();
   tf.bold = true;
   tf.italic = true;


   // TextField 內不含文字內容時,無法套用 bold, italic 樣式
   txt.text = "";
   txt.setTextFormat(tf);
   tf = txt.getTextFormat();
   trace("tf.bold :",tf.bold,", tf.italic :",tf.italic);
   // tf.bold : null , tf.italic : null

   txt.text = "123";
   txt.setTextFormat(tf);
   tf = txt.getTextFormat();
   trace("tf.bold :",tf.bold,", tf.italic :",tf.italic);
   // tf.bold : true , tf.italic : true


   // 改變 TextField.text 內容時,bold, italic 樣式被重設
   txt.text="123";
   tf = txt.getTextFormat();
   trace("tf.bold :",tf.bold,", tf.italic :",tf.italic);
   // tf.bold : false , tf.italic : false

   tf.bold = true;
   tf.italic = true;
   txt.setTextFormat(tf);
   txt.text += "123";
   tf = txt.getTextFormat();
   trace("tf.bold :",tf.bold,", tf.italic :",tf.italic);
   // tf.bold : false , tf.italic : false


   // 使用 appendText 改變 TextField.text 內容時,bold, italic 樣式會被保留
   tf.bold = true;
   tf.italic = true;
   txt.setTextFormat(tf);
   txt.appendText("456");
   tf = txt.getTextFormat();
   trace("tf.bold :",tf.bold,", tf.italic :",tf.italic);
   // tf.bold : true , tf.italic : true
   
   
   // 指定 TextField.text 內容前,呼叫 setSelection,bold, italic 樣式會被保留
   tf.bold = true;
   tf.italic = true;
   txt.setTextFormat(tf);
   txt.setSelection(0, 1);
   txt.text = "456";
   tf = txt.getTextFormat();
   trace("tf.bold :",tf.bold,", tf.italic :",tf.italic);
   // tf.bold : true , tf.italic : true
   
   
   // 改變 TextField.text 內容時,bold, italic 會被重設為 defaultTextFormat
   tf.bold = true;
   tf.italic = false;
   txt.setTextFormat(tf);
   tf.bold = false;
   tf.italic = true;
   txt.defaultTextFormat = tf;
   txt.text = "456";
   tf = txt.getTextFormat();
   trace("tf.bold :",tf.bold,", tf.italic :",tf.italic);
   // tf.bold : false , tf.italic : true
   
  }
 }
}
// Ticore's Blog - http://ticore.blogspot.com/

了解上述特性之後,答案就很明顯了~~

解決方式:
1. 對於同一字體不同的樣式,均嵌入相同的字集
2. 當 TextField.text 內容重設時,自行回設正確的 Bold, Italic 樣式
3. 利用 TextField.defaultTextFormat 設定 Bold, Italic 設定樣式
4. 於 TextField.text 內容重設之前,呼叫 TextField.setSelection(0, 1);

相關連結:
Flash 技巧 - 預先編譯嵌入字體

Read more...