標籤雲

Android (59) ActionScript (52) PHP (14) JavaScript (11) 設計模式 (10) CSS與Html (8) Flex (7) Material Design (6) frameworks (5) 工具 (5) 串流影音 (4) 通用 (4) DB (3) FlashRemoting (3) Java (3) SQL (3) Mac 操作 (2) OpenGL ES (2) PureMVC (2) React Native (2) jQuery (2) AOSP (1) Gradle (1) XML (1) 軟體設定 (1)

搜尋此網誌

顯示具有 ActionScript 標籤的文章。 顯示所有文章
顯示具有 ActionScript 標籤的文章。 顯示所有文章

2010/11/03

flash.net.registerClassAlias 與 Value Object

接續前面的內容,在 Zend_Amf 入門 裡面,透過 gateway 程式我們可以呼叫 PHP 的方法傳回資料
今天來研究一下另一種 Typed Object 的方式,把 PHP 類別 mapping 到 ActionScript 裡面(這種專門用來存放資料的物件稱為 Value Object)

首先回顧一下我們的 gateway,透過 addDirectory 我們把 AMFapp/ 下的 .php 動態載入
<?php
require_once 'Zend/Amf/Server.php';

$server = new Zend_Amf_Server();
$server->addDirectory(dirname(__FILE__) . '/AMFapp/');

$response = $server->handle();
echo $response;
?>

接下來我們在 AMFapp 下面新開一個資料夾 vo,專門用來放 Value Object 的類別
並在裡面建立一個 VOPerson.php
<?php
class VOPerson{
 //注意這裡!! 用 public $_explicitType 設定類別別名
 public $_explicitType = "VOPersonAlias";
 
 public $fName = "Joseph 喬瑟夫";
 public $lName = "Joestar 喬斯達";
 public $favoriteFood = array("T-Bone Steak", "Fried Chicken", "Chewing Gum");
 
 protected $standName = "Hermit Purple";
 private $birthday = "1920-09-27";
}
?>

除了用 public $_explicitType 設定類別別名外,也可以用 getASClassName 回傳類別別名
兩種方式擇一即可
public function getASClassName(){
 return 'VOPersonAlias';
}

有了 mapping 的 PHP 類別後,我們再寫一個 TestVO.php (放在 AMFapp下) 用來回傳這個 VOPerson 類別

<?php
//記得要把類別匯入
include 'vo/VOPerson.php';

class TestVO{
 public function getVOPerson(){
  return new VOPerson();
 }
}
?>

在 Flash 裡面我們也要準備一個跟 VOPerson 對應的類別,本例為 VOPerson.as
範例方便起見就使用 default package
package  {
 public class VOPerson {
  public var fName:String;
  public var lName:String;
  public var country:String;
  public var favoriteFood:Array;
  //非 public 的物件成員是不會 mapping 過來的,這邊只是測試用而已
  protected var standName:String;
  private var birthday:String;
  //這邊我們定義 toString 方法以便傾印資料
  public function toString():String{
   var s:String = "======== " + fName +" ‧ "+ lName +" ========\n";
   s += "國籍: "+ country +"\n";
   s += "喜歡的食物: "+ favoriteFood +"\n";
   s += "替身名: "+ standName +"\n";
   s += "生日: "+ birthday +"\n";
   s += "=================================================";
   return s;
  }
 }
}

該準備的東西都齊了,組合!!
ValueObjectTest1.fla
import flash.net.*;

//注意這裡!! 一定要註冊類別別名且與 $_explicitType 的值相同,這樣才可以正確識別
registerClassAlias("VOPersonAlias", VOPerson);

[Bindable]
var person:VOPerson;

var nc:NetConnection = new NetConnection();
var responder:Responder = new Responder(onNCResult, onNCFault);
nc.connect("http://localhost/zend_gateway.php");
nc.call("TestVO.getVOPerson", responder);

function onNCResult(re:*):void{
 person = VOPerson(re);
 trace(person); //因為我們寫了 toString(),所以可以直接 trace
}
function onNCFault(fault:Object):void{
 for(var s:String in fault){
  trace(s);
 }
}

如果順利的話就可以見到如下資訊
可以看到非 public 的屬性是過不來的
======== Joseph 喬瑟夫 ‧ Joestar 喬斯達 ========
國籍: U.S.A.
喜歡的食物: T-Bone Steak,Fried Chicken,Chewing Gum
替身名: null
生日: null
=================================================

如果出現錯誤訊息的話,請檢察類別別名是否有設定?
在 PHP 跟 AS 裡面設的別名是否相同?
需要的檔案是否正確匯入?...等

2010/11/01

ActionScript (AMF3) 與 PHP 資料型別對照表

ActionScript (AMF3) 對應 PHP 資料型別
ActionScript type (AMF3)PHP type
undefined
null
null
intinteger (超出範圍時為 float)
Number
uint
float
Booleanboolean
Stringstring
Arrayarray
XmlSimpleXml
flash.utils.ByteArraystring
Object
mx.collections.ArrayCollection
object
RemoteClass Objectclass mapped object
dateZend_Date

 

PHP 對應 ActionScript (AMF3) 資料型別
PHP typeActionScript type (AMF3)
nullnull
booleanBoolean
stringString
integer
float
Number
DomDocumentXml
DateTimeDate
Array (索引式陣列)Array
object
Array (關聯式陣列)
Object
RemoteClass Zend_Amf_Value_TypedObjecttyped object
RemoteClass Zend_Amf_Value_ArrayCollectionmx.collections.ArrayCollection

2010/10/25

Zend_Amf 入門

上一篇整理了 Flash 的資料交換方式,這次要開始慢慢切入正題
Flash Remoting 是 swf 使用 AMF 二元資料格式與伺服器的 Remoting Component 進行資料交換的技術(透過 HTTP)
在 PHP 有 amfphp, Zend_Amf 等
但由於 PHP 5.3 與 amfphp 1.9 在 localhost 測試時會出現錯誤
在找不到解決方法下,我打算改由 Zend_Amf 來上手

Zend Framework 是 Zend 公司針對 PHP 企業級開發的 Framework,而 Zend_Amf 就是其中的一組函式庫
取得的方法很簡單,只要上官方網站下載後解壓縮打開即可

而我是使用 svn 的方式來取得,既然是寫入門還是說清楚一點好了:
1. 首先如果 PC 裡沒有安裝 svn 軟體,可以下載安裝 TortoiseSVN (俗稱小烏龜)軟體
2. 在電腦裡開一個資料夾並命名,如 Zend Framework,按右鍵選擇 SVN Checkout,網址輸入 http://framework.zend.com/svn/framework/standard/trunk
3. 此時會跟網址上的檔案進行版本更新,但因為 Zend Framework 並不是很小,所以等它跑完大約需要幾分鐘

至於布署方式,只要把 library 的內容放到網站目錄下即可
(租用虛擬主機空間時由於無法更改主機設定故要用這種方式來布署)
我是選擇直接在 php.ini 裡做 include 設定,檔案就不用貼來貼去占空間
include 的方法如下:只要找到 include_path 這一行,然後以分號分隔把路徑加上去即可
路徑請記得改成自己的...

; Windows: "\path1;\path2"
include_path = ".;c:\php\includes;C:\Zend Framework\library"

這樣安裝跟布署就完成了!!

接下來還有一個重點就是要設定 Gateway 程式
在網頁目錄下新增一個 zend_gateway.php 輸入以下程式碼
並開一個子資料夾來放 remoting component,本例為 AMFapp/

<?php
//匯入 Zend/Amf/Server.php 檔案
require_once 'Zend/Amf/Server.php';

// 建立 Server 物件
$server = new Zend_Amf_Server(); //由於檔案是在 Zend/Amf/ (套件路徑)下,所以 new 的時候要寫為 Zend_Amf_Server
$server->addDirectory('AMFapp/'); //呼叫  Zend_Amf_Server 的 addDirectory 方法,將指定路徑下的檔案自動加進來

//呼叫 handle 方法處理資料並放入 $response 裡輸出
$response = $server->handle();
echo $response;
?>

而在 AMFapp 裡,開一個 HelloWorld.php 來測試吧
<?php
class HelloWorld{
 /**
  * 就是 Hello World 啦!!
  * @param string $arg
  * @return string
  */
 function sayHelloWorld($arg = ""){
  $returnValue = "Hello Zend_Amf!! 如果看到這就成功嚕!!". $arg;
  return $returnValue;
 }
}
?>

接下來是 ActionScript 的部分:(關於 NetConnection 的詳細內容請參閱官方文件)
package {
 import flash.display.*;
 import flash.net.*;
 
 public class MyTest_zend_01 extends MovieClip {
  private var ncZend:NetConnection;
  private var rsZend:Responder;
  
  public function MyTest_zend_01() {
   //建立 NetConnection 物件
   ncZend = new NetConnection();
   //將 Gateway 的完整路徑傳入 connect 方法
   ncZend.connect("http://localhost/zend_gateway.php");
   //建立 Responder 物件,指定回應與錯誤的 callback func
   rsZend = new Responder(onResult, onFault);
   //呼叫 call 方法開始連線
   //注意這裡是用 SomeClass.SomeFunc 的表示方式
   ncZend.call('HelloWorld.sayHelloWorld', rsZend, "這是傳入的字串");
  }
  //回應處理函式
  private function onResult(result:Object):void {
   trace(result);
  }
  //錯誤處理函式
  private function onFault(err:Object):void {
   trace("fault:");
   for (var i:String in err) {
    trace(i, ":", err[i]);
   }
  }
 }
}
測試發布時如果看到 output 有 trace 出訊息就表示成功了!!

2010/10/20

Flash 資料交換方式整理

把已知的 Flash 資料交換方式筆記整理一下 (部分參閱自 shinder 老師書裡的內容,請多多支持 shinder 老師的大作呦)

FlashVars
使用時機:使用 URL-Encoded 字串,故我覺得很適合配合 JavaScript 把 GET 參數在一開始帶入 swf 裡
可以參考此篇舊文
ExternalInterface
使用時機:swf 實體跟它的 Container 進行溝通,例如呼叫網頁上的 JavaScript function 或 JavaScript 呼叫 actionscript function
LocalConnection
使用時機:一個以上執行中的 swf 實體互相進行溝通用
URLLoader
使用時機:透過 GET/POST 傳遞字串資料至 Server 並接收回應
參考此篇舊文
XML
使用時機:以字串方式傳遞結構性、且筆數較少的資料

須伺服器環境配合的有下面兩種:
Flash Remoting
使用時機:使用 HTTP 傳遞 AMF 格式的二元資料(可傳遞 Object 及 Array 等格式),但必須 Server 有相對應的 Remoting Component
Socket
使用時機:及時網路遊戲或聊天室,使用的是 TCP Socket 連線,需要 Socket Server

2010/04/09

Flash 如何在 SWF 檔案中內嵌字型

很久沒寫 blog 的我今天再來寫一篇基礎文章吧

稍微有在寫 actionscript 的人應該碰過這樣的狀況,
就是你想在某個地方放一個動態文字欄位
但是動態文字如果不內嵌字型的話,就會是醜醜的鋸齒狀文字
要是用了使用者電腦沒有的字體,還顯示不出來哩

那麼要如何在SWF檔案中內嵌字型呢?
作法其實要看你的狀況而定

1. 動態文字的內容是固定的
如果動態文字的內容是固定的,這樣的狀況可以考慮用 Flash IDE 的功能把要用的字內嵌在 SWF 檔案中
由於中文字數遠多於英文字母,因此不建議全部嵌入
只嵌入我們要的文字即可
首先建立一個動態文字欄位 embed_txt,然後把你要內嵌的文字內容全部貼進去
接下來在屬性面板打開字元內嵌的對話框
並在"包括下列字元"這個選項,選擇"自動填字",然後按下確定就可以了。
(當然你也可以自己把會用到的字填到這一欄中)
接下來你可以把 embed_txt 裡的字給刪掉,或將他的 visible 設為 flase
嵌入的文字在同一個檔案中是可以共用的
因此同一個檔案如果有其他需要使用相同內嵌字的,只要內嵌一個空白就可以,不用重複嵌入。

2. 動態文字的內容較多或不固定
如果動態文字的內容是不固定或比較多,我們就該考慮是否要把整個字型給嵌入
要嵌入整個字型當然也可以在字元內嵌的對話框中去做。
但這樣整個字型都會包在要執行的 SWF 檔中,好一點的作法是把它變成另一個檔案再載入進來使用
要發布字型的SWF檔案還是要靠 Flash IDE
在 CS4 的 Library (元件庫)面板,點開右上角的功能表,然後選擇"新增字體"
選擇你要嵌入的字體及樣式(如果是要把字體當做點陣圖嵌入的話要順便指定字體大小)
連結部份勾選"匯出給 Actionscript 使用",並指定類別名稱
(順便可以看到他的基底類別是 flash.text.Font)
確定後發布 SWF 檔。這樣我們就有一個字型檔案了
接下來在另一個檔案把它載入吧
開一個新檔案並輸入以下程式碼:
var ldrContext:LoaderContext = new LoaderContext();
var wordLdr:Loader = new Loader();
var myFont:Font;

//指定載入的SWF檔的 applicationDomain 為 currentDomain
ldrContext.applicationDomain = ApplicationDomain.currentDomain;

wordLdr.contentLoaderInfo.addEventListener(Event.COMPLETE, onWordLdrComplete);
try{
 //載入事先準備好有內嵌字型的 SWF 檔案
 wordLdr.load(new URLRequest("DFLiKaiShu-Md.swf"), ldrContext);
}catch(err:Error){
 trace(err);
}

function onWordLdrComplete(event:Event):void{
 //使用  getDefinitionByName 傳入類別名稱
 var fontClass:Class;
 fontClass = getDefinitionByName("Font_DFLiKaiShuMd") as Class;
 //註冊字型
 Font.registerFont(fontClass);
 //如果不知道字型名稱,就把它 new 出來,就可讀取 fontName 屬性
 myFont = new fontClass;
 useFont();
}

var tf:TextFormat;
var t0:TextField= new TextField();
t0.autoSize = TextFieldAutoSize.LEFT;
//embedFonts = true 表示使用內嵌字體
t0.embedFonts = true;
this.addChild(t0);

function useFont():void{
 //字型的名稱如果已經知道的話,不用new出myFont直接填入名稱字串也是可以
 tf = new TextFormat(myFont.fontName, 18); 
 t0.defaultTextFormat = tf;
 t0.text = "這裡的字會是華康儷楷書!!";
}
這樣就可以把內嵌字型給載入進來了,不過字型SWF檔案動輒好幾MB
最好是控制動態文字的字型不要太多,否則讀進這麼大容量的檔案也不是一件好事阿。

2010/01/19

Gaia Framework - API 簡易說明

這幾天把 Gaia API 的官方文件稍微翻譯一下
以下大致整理 Gaia Framework API 方法(AS3)

goto(branch:String, flow:String = null):void
呼叫goto方法前往網站的分支(branch),如果該分支不存在會找到最近的
如果傳入的分支層級超過 site.xml 裡的架構,Gaia會記住該 branch 字串並發出 deeplink 事件,可用 getDeeplink() 得出這種 branch 字串。
第二個參數 flow 的值為 Gaia.NORMAL, Gaia.PRELOAD, and Gaia.REVERSE
例:
Gaia.api.goto("index/nav/people/friends");
Gaia.api.goto(Pages.HOME); //前往"index/nav/home",建議使用這種方式,這樣若架構變更也不會有影響

getPage(branch:String):IPageAsset
傳入branch字串,回傳PageAsset,若字串不是有效的id則回傳null可利用它得到PageAsset物件進而利用content屬性對頁面的成員做操控(看來是擴充自 Loader);PageAsset還有一個屬性children:Object可用來存取其下層物件
例:
Gaia.api.getPage("index/nav/home").content.myProp = value;
Gaia.api.getPage("index/nav/home").content.myFunc();
Gaia.api.getPage("index/nav/home").content.MC_Movieclip.x = 10;

getDepthContainer(depth:String):Sprite
回傳 Sprite 或 MovieClip 深度容器。必須傳入dapth常數。(Gaia.TOP, Gaia.MIDDLE, Gaia.BOTTOM, Gaia.PRELOADER)
例:
var top:Sprite = getDepthContainer(Gaia.TOP);
getDeeplink():String 從GaiaSWFAddress類別回傳超出site.xml領域的深層鏈結。
getSiteTitle():String
setSiteTitle(value:String):void
回傳/設定 該網站的 title 屬性值(包含 %PAGE% 標記)。

getValidBranch(branch:String):String 把傳入 branch 字串轉為有效branch字串
getCurrentBranch():String 回傳目前branch。
setDelimiter(value:String):void 設定網站的分隔符號。完成後需呼叫refreshContextMenu()把ContextMenu更新。
getSiteTree():PageAsset 傳回index頁的PageAsset實體。
getMenuArray():Array 回傳site.xm中所有menu="true"的頁面的陣列。(從上到下排列)
getSiteXML():XML 回傳原始site.xml

getContextMenu():ContextMenu
refreshContextMenu():void

getPreloader():IMovieClip 回傳preloader。可以用它來呼叫自訂方法、重新定位等。
setPreloader(asset:MovieClipAsset):Void 用已載入的 MovieClipAsset 覆蓋preloader。不傳參數呼叫時則恢復預設。
getAssetPreloader():IMovieClip
getAssetPreloader():IMovieClip

getDefaultFlow():String
setDefaultFlow(flow:String):Void
回傳/設定網站的預設flow。值為 Gaia.NORMAL, Gaia.PRELOAD, Gaia.REVERSE 或 Gaia.CROSS。

Gaia.api.addAssets(nodes:XMLList, page:IPageAsset):void 在runtime為頁面添加外部動態assets 。

getWidth():int
getHeight ():int
回傳stage原始 寬/高

getSitePosition():Object 以Object型態回傳目前Site View的x, y位置。對於要網站置中時有用。
setLoadTimeout(value:int):void 調整Gaia在載入branch時的容許等待時間,以毫秒為單位,預設值為10000。
setPreloaderDelay(value:int):void preloader呼叫transitionIn()的延遲時間(防止從快取載入時,preloader先跑出來)。預設150毫秒,可傳入的最小值為1。

setGlobalVolume(value:Number, duration:Number = 0; onComplete:Function = null):void 設定整個網站的全域數值。如果有傳入duration參數,它會在指定時間內漸變到該數值。如果有傳入onComplete參數,會在漸變完成後呼叫該function。
getGlobalVolume():Number 回傳目前全域數值。

getAvailableFonts():Array 回傳使用Runtime Font Loading成功註冊的所有字體類別名稱的陣列。
getFontName(className:String):String


SWFAddress Proxy方法

back():Void
forward():Void
getTitle():String
setTitle(title:String):Void
href(url:String, target:String):Void
popup(url:String, name:String, options:String, handler:String):Void
setHistory(b:Boolean):Void 除非你在site.xml的site節點設定history="false",否則預設是開啟。
getHistory():Boolean
setTracker(s:String):Void 設定瀏覽追蹤函數。預設值為'urchinTracker'。
getTracker():String
getBaseURL():String

2009/12/09

用於 Flash 網站前端開發的 GAIA Flash Framework-1

GAIA Framework For Adobe Flash
是一個開放原始碼的 Flash 網站前端開發 framework
支援 AS3 與 AS2
整合 SWFObject, SWFAddress, TweenLite, DeMonster Debugger 等相關的東西
目前最新版是 Version 3.1.9

Adobe TV 裡有一段約一小時的影片是作者 Steven Scaks 對於 GAIA Flash Framework 做的介紹
http://tv.adobe.com/watch/fitc/gaia-framework-for-adobe-flash/
看完之後感覺用這個來做 flash 網站的話應該是會蠻快的
可以專心在製作頁面內容上

想玩玩看的話可以上官方網站 http://www.gaiaflashframework.com/
下載這個 framework 的 mxp 檔,安裝在 Flash CS3 或 CS4
或是先在該站首頁的左側看看那些使用本框架做出來的酷炫網站

官方的文件我稍微看了一下
目前的感覺是這個 framework 的確如作者所說
不會試圖改變開發者原本的習慣
而是提供快速的方法來幫助架構的建置
整個框架似乎還蠻好了解與上手的
而且是開放原始碼所以便於修改及研究
但還是要真正拿來實做一下才會知道好不好用
doc 也要詳細 k 一下才能了解所有的機制跟功能

後續文章會把 study 官方網站的 doc 後做一些整理...
但何時會有後續咧...我也不確定耶

2009/10/20

Flash 的 cookie -- SharedObject 類別

今天要講的是已經存在很久我卻一直沒有機會用到...可以看作 "Flash 的 Cookie"的 ShareObject 類別(flash.net.SharedObject)

這個類別可以把資料存進使用者電腦本機裡
比 cookie 好用的地方在於,它可以存放如 Array 或 Object 這樣的物件資料型態
這樣同一網域下的不同 swf 檔也可以共用資料了
廢話不多說,直接介紹要怎麼用吧~~
(這邊只介紹本機 SharedObject,更詳細用法或遠端 SharedObject 請直接查官方 doc)

1. 建立或取得 SharedObject
先建立一個 SharedObject 實體,然後使用 static 方法 SharedObject.getLocal(name:String, localPath:String = null, secure:Boolean = false) 依照傳入的名稱取得 SharedObject 回傳,若不存在則會建立
例:
var share_so:SharedObject;
share_so = SharedObject.getLocal("localVar");

2. 把需要存放的資料放進 SharedObject 實體的 data 屬性,注意不可直接將資料指給 share_so.data 否則會被忽略
刪除 data 裡的某個資料應使用 delete
例:
share_so.data = this.myData; //無效
share_so.data.myData1 = this.myData1; //正確
share_so.data.items = items_array; //複雜資料型態
share_so.myData2 = this.myData2; //可以,但其他同網域下的 swf 無法存取該屬性,且在該 swf 關閉後也不會被存在本機裡
delete share_so.data.myData3; //刪除 myData3 的資料 (將 myData3 設為 null 或 undefined 並不會刪除它)

3. SharedObject 會在被關閉前自動寫入本機,但可以呼叫 flush(minDiskSpace:int = 0) 立即將 SharedObject 寫到本機。
minDiskSpace 為要求空間大小的位元組(建議一次要夠,因為如果可存取空間小於 minDiskSpace 的話,flash player 會跳出對話方塊要求使用者加大允許空間)
這個方法會回傳 SharedObjectFlushStatus.PENDING 或 SharedObjectFlushStatus.FLUSHED
例:
var flushResult:String = share_so.flush();
if(flushResult == SharedObjectFlushStatus.FLUSHED) trace("寫入完成!");
else if(flushResult == SharedObjectFlushStatus.PENDING) trace("配置的空間不足以儲存此物件");

4. 其他重要屬性
size:uint (ShareObject 目前大小,以位元組為單位。)


不過有幾點要注意:
1.swf檔的尺寸必須大於 215x138。這是為了要在 swf 跳出對話方塊,以便使用者可以更改本機存放的資料大小設定(預設是 100KB)
2.由於存放資料的空間大小是使用者可以變更設定的,所以資料有可能會因為使用者變更設定而遺失
3.隱私權方面,swf 檔僅能讀寫在自己網域內的 SharedObject(但存在本機上的 swf 檔可以隨時將其他網域的共享物件寫入磁碟。)

2009/10/14

為 swf 自訂右鍵選單

這小技巧其實已經用了很久了
但是竟然一直沒有在這個 blog 裡寫一篇關於這個的備忘
今天來補一下吧

InteractiveObject 類別下層的每一個物件都可以有一個唯一快顯選單,可以將 Stage 屬性 showDefaultContextMenu 設為 false 移除選單中所有預設的命令( 除了「設定」和「關於」以外 )。
那要怎麼自訂快顯選單咧~~
先建立一個新的 ContextMenu 類別實體、呼叫 hideBuiltInItems() 方法,並將該實體指定給該 DisplayObject 實體的 contextMenu 屬性。

下面來看看簡單的 Demo Code:

import flash.net.*;
import flash.ui.*;

....(省略)

private var customMenu:ContextMenu;
private var customMenuItem:ContextMenuItem;

....(省略)

//===============================
//custom ContextMenu setup
private function initContextMenu():void {
 customMenu = new ContextMenu();
 customMenuItem = new ContextMenuItem("By Edward Lo");
 customMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, contextMenuHandler);
 customMenu.hideBuiltInItems();
 customMenu.customItems.push(customMenuItem);
 this.contextMenu = customMenu;
}
//ContextMenuEvent Handler
private function contextMenuHandler(e:ContextMenuEvent):void {
 navigateToURL(new URLRequest("http://edscb.blogspot.com/"),"_blank");
}
//===============================

2009/10/09

TextField 的 htmlText 所支援的標籤

從 Flash 外部讀入文字資料,放入 TextArea 組件裡呈現時
往往都會覺得文字的編排不美觀
這時候就要靠 html 標籤來為文字資料指定樣式
但網頁設計師可別高興得太早...Flash 支援的 html 標籤可是很有限阿
不過做些簡單編排的話是還算夠用的
以下把 Flash 支援的 html 標籤做個整理 (又在做沒營養的事情....)

<a>
可用屬性:target、href
<font>
可用屬性:color、size、face (用法與 font-family 同)
<img> 可以塞 SWF (表示它其實是個 Loader 來著)
可用屬性:src、id (可藉 id 以 AS 進行控制)、width、height、align ( left 或 right)、hspace (預設為 8 )、vspace (預設為 8 )、checkPolicyFile
<p>
可用屬性:align (有效值為 left、right、justify 和 center)、class (由 flash.text.StyleSheet 物件定義的 CSS 樣式類別 )
<span>
可用屬性:class (由 flash.text.StyleSheet 物件定義的 CSS 樣式類別 )
<textformat>
可用屬性:blockindent (區塊縮排)、indent (首行縮排)、leading (行距)、leftmargin、rightmargin、tabstops

以下這些就不用多做介紹了:
<li>項目符號(不排序)
<b>
<i>
<u>
<br>

2009/10/08

為 TextField 的 html 超連結加入事件機制

在 Flash 裡,文字欄位可以直接在屬性面板裡面設定超連結與目標視窗(target)
這樣做的話滑鼠移動到該文字欄位時會變成手指圖示

那麼若是超連結需要動態指定時,如何使用 ActionScript 3 達到相同效果呢?

昨天我就遇到了這個問題
一開始我在 TextField 監聽 MouseEvent.CLICK 事件,並指定處理函式負責連結到不同位置的功能
功能上是沒問題,但這樣一來滑鼠游標就不是原本想要的手指圖案,而是文字的" I "圖示了
本來想直接在文字上面放一個透明 MovieClip 就解決了
但今天還是不甘心查了一下,想知道 Flash IDE 是怎麼做的
往 TextField 的 htmlText 屬性去查,果然一查就查到了!!
原來要在 TextField 的 htmlText 指定 <a> 標籤裡的 href 去發出 TextEvent.LINK
趕快記下來:

(前略)...您可以使用 link 事件,讓連結執行 SWF 檔中的 ActionScript 函數,而不是開啟 URL。 若要指定 link 事件,請使用事件結構,而不是您的 href 特質中的 http 結構。 例如使用 href="event:myText",而不是 href="http://myURL"。當使用者按一下包含事件配置的超文字連結時,文字欄位會傳送其 text 屬性設定為 "myText" 的 link TextEvent。 接著,您可以建立於傳送 link TextEvent 時執行的 ActionScript 函數。 您也可以使用樣式表,定義錨點標籤的 a:link、a:hover 及 a:active 樣式。

之前都沒有接觸過 TextEvent,這下子學到了!!
以後可不能什麼都習慣用 MouseEvent 阿.....

2009/10/07

如何使用 AS3 + SWC 在 FlashDevelop 裡進行開發

Flash Develop 是使用 .NET 2.0 架構與 C# 語言所實作出來針對開發 Flash 平台的程式編輯器
除了提供了不錯的編輯環境外,它還針對 Flash 的開發提出了不錯的 workflow

這次要來談一談如何使用 AS3 + Flash IDE 發布的 SWC 元件在 Flash Develop 裡進行開發
(本篇只討論開發流程,不介紹安裝與設定方面的細節,若需詳細資訊可參考 flashdevelop.org 官方文件)

0. 專案建立
 在 FlashDevelop 裡建立專案(官方建議是 AS3 Project with preloader,但如果是較簡單專案可選 AS3 Project 就好)

1. 元件製作
 (1) 視覺部分在 Flash IDE 裡繪製 (原始檔存在專案的 src 資料夾內),也可以做時間軸動畫,但唯一要注意的是元件與其子元件的在元件庫裡的命名最好是相關而有意義的,否則很容易重覆或搞混
 (2) 做好後在元件庫選該元件的右鍵"屬性"或"連結",勾選"匯出給 ActionScript 使用",並設定類別 (建議就是元件名稱,但建議加 package 以免混淆) 與基底類別 (預設 flash.display.MovieClip,但若元件本身沒有時間軸動畫建議改為 Sprite)
 (3) 發布選項記得勾選 "匯出SWC",發布路徑選擇專案的 lib 資料夾內

2. 程式撰寫
 (1) 在 Flash Develop 裡為元件建立程式邏輯,官方提出了"繼承"與"組合"兩種方式,但建議是使用"組合"的方式,Demo Code 如下:
// composition (safe choice)
package {
 import flash.display.Sprite;

 public class MySymbol extends Sprite{
  private var design:MySymbol_design;

  public function MySymbol(){
   trace("I'm a MySymbol instance called", name);
   design = new MySymbol_design();
   addChild(design);
   // custom properties of design
   design.text = "some text";
   design.showText(); //可呼叫時間軸上的 function...但我個人不建議在 Flash IDE 寫任何 code
   design.txtLabel.x += 100;
  }
 }
}
 (2) 在專案的 Main Class 裡,new 出 MySymbol 並使用 addChild 加進來

這樣就可以建立有自己程式邏輯的視覺元件在 FlashDevelop 專案內使用
唯一要注意的是元件的命名千萬別搞混
若還有不清楚的地方請詳閱 flashdevelop.org 官方文件:AS3:FlexAndFlashCS3Workflow

2009/09/23

ActionScript 3.0 的事件模型

(於 200909 整理舊文後重寫)

Flash 的事件模型中有幾種角色:
1. 事件發出者 -- 負責發出事件及傳遞事件實體
(1) 自定義的類別要成為事件發出者最簡單的方式,就是 extends EventDispatcher。因為事件發出的方法 dispatchEvent,就定義在 EventDispatcher 裡面
(2) 如果此類別已經擴充其它類別,可以改為實作 IEventDispatcher 介面、建立 EventDispatcher 成員,然後撰寫簡單的攔截程序將呼叫遞送到彙總的 EventDispatcher。
(3) 事實上, EventDispatcher 是一個很上層的類別, 所以子系類別很多, 舉凡 SimpleButton, Sprite 等等都是。

2. 事件實體 -- 事件的常數字串會定義在這邊,實體是被事件發出者產生
(1) 最簡單最上層的就是 Event 類別,可以繼承他然後自己寫出自定義的事件實體。你可以自定義事件的建構子參數中定義任何你想傳遞給監聽者的資料
(2) 建立自定義事件時,必須覆寫 Event.clone() 方法,才能讓其複製自訂的屬性。否則這些屬性將無法在偵聽程式處理重新傳送的事件時,提供正確的值。

3. 監聽者 -- 負責接收事件實體並處理事件
透過事件實體,監聽者可以完全不管事件發出者的屬性跟方法。只要利用 addEventListener(事件類別.事件常數, 事件處理函式) 的方法針對事件去監聽並指派處理函式,來完成事件的處理即可。


來看看簡單的範例吧

事件實體:
package edlo.events{
//import
import flash.events.Event;

public class DataInsideEvent extends Event{
/* ======= Event const ============================== */
public static const DATA_INSIDE:String = "dataInside"; //自定義的事件常數

/* ======= attributes =============================== */
private var _data:Object;

/* ===============================================
* constructor
* =============================================== */
public function DataInsideEvent(type:String, data:Object=null, bubbles:Boolean = false, cancelable:Boolean = false):void{
super(type, bubbles, cancelable);
this._data = data;
}
/* ===============================================
* functions
* =============================================== */
public override function clone():Event{
return new DataInsideEvent(type, this._data, bubbles, cancelable);
}
/* ===============================================
* Setter & Getter
* =============================================== */
public function get data():Object{
return this._data;
}
}
}

事件發出者:
...(略)
//在類別宣告前用後設標籤宣告此類別會發出什麼事件
[Event(name=DataInsideEvent.DATA_INSIDE, type="DataInsideEvent")]
....(略)
//這邊的例子是本身的MouseEvent.CLICK事件觸發後,發出一個自定義的事件給外面
private function onItemClick(e:MouseEvent):void {
dispatchEvent(new DataInsideEvent("dataInside", {itemName: e.currentTarget.name}));
}
...(略)

事件監聽者:
...(略)
content.addEventListener(DataInsideEvent.DATA_INSIDE, onMenuItemClick);
...(略)
private function onMenuItemClick(e:DataInsideEvent):void {
trace(DataInsideEvent.data. itemName);
}

如果不需傳遞什麼參數的話...可以用 Event 類別作為事件實體....這樣就不必專門寫一個事件實體出來
再偷懶一點的話可以一個類別自己發出事件自己監聽
看情況提供作為參考嚕

以上
只要可以搞懂 AS 3 事件模型的概念
相信對於整個 ActionScript 的了解程度上面會更進一步
開發時在架構規劃上也是會很有幫助的

2009/06/11

Flash IDE 匯出 SWC 供專案使用

現在 Edward 都是用 Flash Develop 來寫 Actionscript 的 code 了
不過一些牽涉到視覺的元件還是必須透過 Flash IDE 來做發佈
且命名上面也是一個問題
這樣實在是很鳥
雖然知道這要用匯出 SWC 的方式來解決
可是一直沒有用過
剛好今天逛網路看到了關於這方面的分享
趕快記錄下來

其實方法很簡單:
1. 在 Flash IDE 裡開一個檔案, 把要匯出的元件作好放在裡面
2. 元件設定好類別連結(建議可用 package 做個分類)
3. 發布設定中要勾選 "匯出SWC", 並把產生的 SWC 檔放在專案路徑下(建議是 libs 資料夾)
4. 進 Flash Develop 將該 SWC 右鍵點選 "Add To Library", 就可以 import 在 SWC 裡面的類別了
(或是在專案屬性的 SWC Libraries 裡填上 SWC 檔名及路徑)

Flex Builder 的作法也差不多
在Project -> Properties-> ActionScript Build Path -> Library Path -> Add SWC
輸入 SWC 檔名及路徑即可( libs 資料夾內的會自己抓, 不用另外設)

不過 Flex Builder 不可以直接在 MXML 加進 SWC 裡的物件
這要怎麼辦呢!!??
在 CS3 有一個 Flex Component Kit for Flash CS3 的 Extension
安裝後在"命令"選單裡會多出 Make Flex Component 選項
點選後再匯出就可以了

2009/06/06

關於 Actionscript 的後設標籤(Metadata Tags)

使用 Flex SDK 編譯時
可以在類別宣告外加上後設標籤(Metadata Tag)
基本上就是給編譯器看的一些設定

根據 Adobe 在 Flex3 的 Live Doc 裡面所描述, 可以在 ActionScript 類別檔使用下面的 Metadata Tags:

[ArrayElementType("elementType")]
// 幫 Array 的 Element 宣告型別

[Bindable(event="eventname")]
//若省略eventname則為"propertyChange"

[DefaultProperty("propertyName")]
//為 component 指定預設值, 詳見Adding properties and methods to a component

[Deprecated]
//"不建議使用"的宣告

[Effect(name="eventNameEffect", event="eventName")]
//效果設定

[Embed(source="filename",mimeType="mimeTypeString")]
//在編譯時內嵌指定的檔案(檔案格式與MimeType可參考這裡)

[Event(name="eventName", type="package.eventType")]
//事件設定

[Exclude(name="label", kind="property")]
//Flex Builder tag inspector 省略檢查該屬性

[ExcludeClass]
//Flex Builder tag inspector 省略檢查該類別

[IconFile("fileName")]
//幫 component 指定 IconFile

[Inspectable(attribute=value[,attribute=value,...])]
//與code hints 還有屬性檢查有關

[InstanceType("package.className")]
//IDeferredInstance 類型的物件設定data type

[NonCommittingChangeEvent("event_name")]
//在設定的Event發生時不要進行檢查

[RemoteClass]
//使用Action Message Format(AMF)時讓 Flex Builder 先保留(不指定)類別資訊

[Style(name="style_name"[,property="value",...])]
//自訂Style屬性資料

[Transient]
//當使用[RemoteClass] 將 AS Object 給 mapping 為 Java object 時, 加了此設定的屬性在送到 server 時會被忽略
-------------------------------
doc上沒寫的:

[SWF]
//例:[SWF(frameRate="30", width="1024", height="576", backgroundColor="#000000", pageTitle="Edward Design")]


目前我比較常用到 [SWF] 跟 [Event] 這兩個
其它的以後有機會再慢慢試嚕

2009/05/06

for .. in 跟 for each.. in 迴圈

本文技術等級: 低

這兩個迴圈雖然會用到, 但每次要用的時候都給它小忘記
還是在這邊做個筆記好了

for .. in 迴圈
說明: 在我之前寫過的 flashvars 文章中就有用過了, 此迴圈會取出物件的所有屬性
例:(把 flashvars 的 code 拿來貼...)
var flashvars:Object = stage.loaderInfo.parameters;
var vars:Object = [];
var k:String;
for(k in flashvars){
vars.push({key:k, value:flashvars[k]});
}

for each .. in 迴圈
說明:此迴圈會取出物件的所有屬性值, 由於知道了屬性名稱後當然可以取出其值, 所以 for each .. in 跟 for .. in 事實上是很相似的, 不過特點在於它可以用 E4X 來操作 XML 檔案, 這一點就很棒, 引述官方的說法於下: "for each..in 陳述式是新的 E4X 語言擴充功能,不只可針對 XML 物件使用,也可針對其它物件與陣列使用..."
例:
for each(var element:XML in myXML.elements()) {
//將 XMLList 物件 myXML 裡的每一個 element 取出
......
}
也可以將上例的 XMLList 物件換成取出 XML 物件內的資料, 只是在 in 後面接的也要改成 XML的第一個子節點

這樣應該清楚了
要是再忘記就在上來偷看一下吧^^

2009/04/17

MOUSE_OVER 跟 ROLL_OVER

這一點相信是一定會讓初學者困擾的問題
在 Flash 的 MouseEvent 裡面有兩組很相似的事件
就是 MOUSE_OVER, MOUSE_OUT 跟 ROLL_OVER, ROLL_OUT
長期以來我也一直不是很清楚

之前有人說分別在於 MOUSE_OVER 這組會一直觸發, 而 ROLL_OVER 這組只會觸發一次
這樣說其實是不對的

在網路上搜尋了一下
很快的找到結論
趕快記下來免得以後又搞混

真正的差別在於
MOUSE_OVER 與 MOUSE_OUT 在事件的傳遞上面會 bubbling 上去
也就是偵聽該事件的實體若還有 child 實體存在
則 child 實體也會觸發該事件
也就是說在事件偵聽函式中得到的 target 屬性(觸發者)未必會是偵聽該事件的實體
而有可能會是它的 child
(但 currentTarget 會是偵聽該事件的實體)

而 ROLL_OVER 跟 ROLL_OUT 則比較特殊
只有偵聽該事件的實體會觸發
其 child 實體不會多觸發一次事件
如果 child 實體也註冊了 ROLL_OVER 跟 ROLL_OUT 事件
則事件實體會有兩個
(相同的狀況在 MOUSE_OVER 與 MOUSE_OUT 這一組則會是只有一個事件實體, 但在 bubbling 階段廣播到不同實體)

以往概念不清楚時我常常用麻煩的方法
叫物件實體去偵聽 MOUSE_OVER 與 MOUSE_OUT
卻又不希望child 實體來干擾
所以會去停用物件實體的 mouseChildren 屬性
並使用事件的 currentTarget 屬性
觀念清楚後發覺自己怎麼這麼笨....
遇上這種狀況只要偵聽 ROLL_OVER 跟 ROLL_OUT 就好了阿
不過 MOUSE_OVER 與 MOUSE_OUT 也還是有它適合的狀況歐
要視不同狀況善加利用內建的事件才是最好的^^

參考網站:(他做了範例, 概念馬上就很清楚)
http://www.zedia.net/2008/difference-between-mouseeventroll_over-and-mouseeventmouse_over-in-as3/
另外在 Ticore 的網站也很久之前就討論過
http://ticore.blogspot.com/2007/08/as3-mouseover-rollover-2.html

2009/03/19

將 Array 裡的物件依照自訂規則做排序

這是今天遇上的一個小問題
還好查過 doc 之後豁然開朗
趕快記錄在這邊

故事是這樣的
我用了一個 Array 存放了一些 MovieClip
並希望他們在做某個動作之前先照他們的 y 軸數值做排序
一開始我用的是 Array 的 sortOn 方法
如下:
myArr.sortOn(y, Array.NUMERIC);
但結果並不如預期是照 y 的數值去排列
(很奇怪..不知出問題的原因為何...)

原本打算自己寫個 Function 來解決
但後來又仔細查了 doc
發現 sort 方法有一個參數
可以指定某個自訂 Function 讓 sort 方法依此來做排序
簡單 code 如下:

/*將 Array 裡的物件照自訂規則排序
* 此 Function 要傳入兩個參數並回傳 Number */
myArr.sort(sortOnMyRule);

/*自訂的排序 Function */
private function sortOnMyRule(a:DisplayObject, b:DisplayObject):Number {
if (a.y > b.y) return 1; //將 a 排在 b 的前面
else if (a.y < b.y) return -1; //將 a 排在 b 的後面
else return 0; //排序優先順序相同
}

這樣 Array 就會依照傳回的值把裡面的物件排序完成, 太棒了!
以後要更專心看 doc 才行....

2009/03/18

矩陣迴旋濾鏡-ConvolutionFilter

flash.filters.ConvolutionFilter 將輸入影像內的像素和鄰近的像素結合產生影像。達到包含模糊、邊緣偵測、銳利、浮雕和斜角各種效果。

適用物件, 套用方式與尺寸限制: 與 ColorMatrixFilter 同

屬性:
matrix : Array
//用於矩陣變化的值陣列。必須等於 matrixX * matrixY
//矩陣迴旋係依據 n x m 矩陣,來描述輸入影像內的指定像素值如何與鄰近像素值結合以產生結果像素值。每一個結果像素都是根據將矩陣套用到對應的指定像素及其鄰近像素所決定。
//對於 3 x 3 矩陣迴旋,下列公式可用於每一個獨立的顏色色版:
//dst (x, y) = ((src (x-1, y-1) * a0 + src(x, y-1) * a1....
// src(x, y+1) * a7 + src (x+1,y+1) * a8) / divisor) + bias

matrixX : Number //矩陣的 x 維度 (矩陣的行數)。
matrixY : Number //矩陣的 y 維度 (矩陣的列數)。

divisor : Number
//預設值為 1。 除數值是所有矩陣值總和除以結果的總顏色飽和度。 若值是 0 則忽略,改用預設值。

bias : Number
//增加至矩陣變化結果的偏差值量。偏差值會增加每個色版的顏色值,可讓深顏色看起來明亮一點。 預設值為 0。

preserveAlpha : Boolean //是否保留 Alpha 色版而未保留濾鏡效果,或是否套用到 Alpha 色版及顏色色版。
clamp : Boolean //是否應該固定影像。
color : uint //用來替代原始影像中像素的 16 進位顏色。
alpha : Number //替代顏色的 Alpha 值。


建構子:
ConvolutionFilter(
matrixX:Number = 0, matrixY:Number = 0,
matrix:Array = null,
divisor:Number = 1.0, bias:Number = 0.0,
preserveAlpha:Boolean = true, clamp:Boolean = true,
color:uint = 0, alpha:Number = 0.0)

//把所有參數初始化給 ConvolutionFilter 實體就對了

方法:
clone():BitmapFilter
//傳回此濾鏡物件的副本。

簡單範例如下:
var blur:Array =
[0,1,0,
1,1,1,
0,1,0];

var sharpen:Array =
[0,-1,0,
-1,5,-1,
0,-1,0];

var edge:Array =
[0,-1,0,
-1,4,-1,
0,-1,0];

var emboss:Array =
[-2,-1,0,
-1,1,1,
0,1,2];