Joey Lott ( www.person13.com )著
李易修 ( www.lis186.com ) 譯
別讓建立自訂組件嚇到你。雖然組件可能很複雜,事實上它們只是比較特別的movie clip。不論你知不知道如何製作movie clip,你都可以製作組件。你唯一需要了解的就是ActionScript 2.0類別怎麼寫。如果你還不知道如何撰寫ActionScript 2.0類別,你可以先到http://www.person13.com/articles,?..t入門系列文章。
本文將探討的議題有:
* 組件的好處。
* 建立組件的影片片段 (component movie clip)。
* 撰寫基本的組件類別 (component class)。
* 連結組件類別與影片片段。
* 匯出壓縮的影片片段 (compiled clip)。
你可能已經發現上面列出的議題,並不包含如何擴充v2 component framework。我不在本文中探討V2 component有幾個原因。第一我認為重頭開始製作組件,應該會比擴充Macromedia的V2 component更容易了解組件的架構。除了V2 framework提供了style和focus management等幾個不錯的功能,我找不到v2 framework太多的優點,值得增加這麼多的檔案容量到.swf。舉例來說,如果你增加了ProgressBar組件到空的Flash文件內,並輸出,檔案大小已經是27KB。如果你擴充了v2 framework,你可以確定檔案大小一定大於Macromedia的ProgressBar。
如果你你想要擴充v2 framework,這篇文章也有一些你想知道的基本概念。當你了解了這些之後,你就已經準備好如何利用v2 framework了。
組件的好處
在你開始學習建立組件之前,你很可能想先了解組件的優點。雖然組件只是特殊的movie clip,不過組件也可以很強大。這是一個全體大於部份的總和的例子。
就像Flash內建的基本UI component。你也可以建立一個自訂的combobox或是按鈕控制項,需要的時候就可以直接使用。你也可以先繪製圖形,然後在主時間軸寫大量ActionScript程式碼,完成類似的工作。但是我確定把組件拖曳到場景裡、設定參數,一定簡單的多。這個簡單的例子說明了許多組件的好處。組件包含了可再用的功能,並以某種形式封裝,讓你只要把組件拖曳到場景上就可以利用了。此外,組件讓你使用圖形使用者介面設定參數 (Component Inspector panel, 組件檢測器) 或使用API。這代表你可以使用ActionScript控制組件強大的功能,也可以使用組件檢測器方便的設定參數。
不只有組件能封裝功能,但它們可以讓功能更容易的散佈出去。如果你想要讓別人使用你製作的組件,你要做的只有包裝、傳送它。只要點幾下滑鼠,組件就會安裝好了。此外,如果你把組件包裝成.swc檔,程式碼相對的就受到比較好的保護。(雖然有一些反組譯程式以樣可以取得你的ActionScript程式碼。)
建立組件的影片片段 (Component Movie Clip)
除了某些例外情況外,你必須在runtime附加 (attach)或載入所有的圖像到組件內。這代表你要用ActionScript處理所有的事情。因此,組件的影片片段(component movie clip)真的很簡單。然而, 有幾件事情你必須要記得:
* 組件只會顯示邊界內的圖像,而邊界是在編輯時定義在movie clip內的。這聽起來很奇怪。這代表如果你在編輯時,沒有在component movie clip內定義圖像,那麼附加或載入的圖像都不會被顯示出來。解決的方法就是在movie clip的第一個影格內,定義一個方形的影片片段實體 (rectangular movie clip instance)。我通常稱這個實體為mcBoundingBox。mcBoundingBox應該能夠符合所有組件圖像的尺寸。
* 為了能夠正確的輸出.swc檔案(本文稍後將介紹如何製作),組件元件(component symbol)內需要包含所有由程式碼附加的元件。此外,其他元件不會被匯出到.swc內。因此,因此,我建議在component movie clip的第二個影格,加上所有由程式碼附加的實體。
* 你的component movie clip元件將會有兩個影格 - 第一個影格包含mcBoundingBox實體。第二個影格包含所有想要附加的元件。請記得在第一個影格,加上stop()。
建立組件的類別 (Component Class)
組件至少包含一個影片片段元件和一個相關的ActionScript類別。你應該已經知道如何建立影片片段元件,因此本篇文章我門只探討如何建立ActionScript類別。如果你已經知道如何撰寫基本的ActionScript 2.0類別,這個部分將會相當的簡單。
組件類別應該由MovieClip類別擴充。由MovieClip類別擴充組件類別,可以讓組件繼承MovieClip類別中所有的屬性與方法。這代表你可以使用ActionScript控制組件的位置、顯示與否和透明度等等。這也代表你可以在類別內使用createEmptyMovieClip()和 attachMovie()在組件內增加巢狀的元素。舉例來說,你可能想要為你的組件建立一個基本的類別,以提供一項通用的功能。這個類別應該由MovieClip擴充,其他的類別則應該由此類別擴充。
元件類別有幾個特殊的方法可以(需要)實做。我們會一一說明這些方法。首先,我們先建立一個基本的類別作為例子。
代码:
class com.person13.SampleComponent extends MovieClip {
// 為了讓程式碼可以參照,你必須宣告類別成員。
// 在這個例子當中,mcBoundingBox是在組件元件中,做為邊界的movie clip的名稱。
private var mcBoundingBox:MovieClip;
function SampleComponent() {
// 建構式能夠呼叫其他方法,避免直接再建構式內寫一堆程式碼。
// 它能夠幫助你組織程式碼。你將會看到建構式能夠帶來的好處。
init();
}
private function init():Void {
// 通常你想要設定邊界方塊為不可見的,尺寸也設定為0。
// 邊界方塊在編輯時的尺寸代表影片播放時,組件顯示的範圍,
// 但組件在播放時可以隱藏。
mcBoundingBox._visible = false;
mcBoundingBox._width = 0;
mcBoundingBox._height = 0;
}
}
前面的類別是最基本的組件類別。你應該確定類別是由MovieClip擴充,並且隱藏了邊界方塊的實體。這些程式碼並不長,我只是想讓你 a)知道不需要寫多餘程式碼 b)了解每個部分的程式做了些什麼事情。
就像上面程式碼的註解,我建議你在建構式內呼叫其他方法,而不要在建構式內加入太多功能。我通常實做了下面的幾個方法,並在建構式中呼叫:
* init() - 此方法包含初始化的所需要的程式碼。我通常把實體的縮放比例設定為100%,理由容後再述。另外,我也在這裡隱藏邊界方塊,並初始化此類別,讓它能夠派遣 (dispatch)事件(後面會做解釋)。
* createChildren() - 用來附加或建立所有movie clip和text field等等的方法。 通常包含attachMovie()和/或createEmptyMovieClip()。
* draw() - 此方法處理所有需要用程式繪圖的部份。並不是所有的組件都需要畫什麼東西。
* arrange() - 佈置所有的圖像到正確的位置。通常組件存在之後, arrange()方法會被呼叫很多次。舉例來說,每次組件的大小被調整,我們通常需要調整組件內元素的位置。
後面你將會看到這些方法的實做範例。
連結組件類別和影片元素
你定義了基本的影片片段元件和元件類別之後,接下來就應該把這兩個部分連結起來。當一個movie clip的實體被建立 - 不論是拖曳實體到舞台上或使用程式碼附加到舞台上 - Flash通常把此元件連結到MovieClip類別。但你想要讓Flash把元件的連接到你的自訂類別,如此這個實體才能存取你在類別內建立的功能。
你可以修改元件的連結設定 (linkage settings)中ActionScript 2.0類別,以設定movie clip所連結的類別。 要開啟movie clip的連結設定,可以在元件庫內的元件上按滑鼠右鍵/command-click,選擇連結設定。連結設定中你需要設定:
* 勾選匯出給ActionScript使用。
* 設定元件的識別名稱。
* 在AS 2.0類別欄位內設定類別。 你應該提供完整的類別名稱 (fully-qualified class name)。這代表如果類別在com.person13套件內,你就需要包含套件名稱。
你設定好元件連結的類別之後。當你建立了元件的實體,Flash會自動讓實體連結到指定的類別,取代預設的MovieClip。
增加參數 (Parameters)
雖然你可能想建立能由API控制的組件,但是在大多數的狀況下你也會想讓元件的實體能夠由組件檢測器設定參數 - 讓不懂AcgtionScript的人也能使用它。這也是組件的好處之一。
如果你利用Flash MX建立過組件,你應該記得你是在組件定義對話框中定義參數的。 在Flash MX 2004中,這個對話框仍然存在,但是已經不建議使用。 當你在Flash MX 2004中使用ActionbScript 2.0類別建立組件,你應該在類別內使用特殊的metatag定義參數。 使用metatag定義參數的方式比之前好太多了。最大的有優點就是效率比起之前愚蠢的對話框好多了。
[Inspectable] metata告訴Flash這是為組件設定的參數。如果你在類別內使用了[Inspectable] metatag在任何屬性之前(包含getter和setter方法),這個屬性就會自動變為參數。除了getter和setter之外,我通常不主張把屬性定義為公開的。所以,下面的例子,我將只使用getter和setter方法。但是你也可以把 [Inspectable] 放在公開的屬性前,這樣一樣能夠運作。
下面的例子告訴你,[Inspectable] 標前能夠被放置在getter或setter方法前,使其成為一個參數。
代码:
[Inspectable]
public function set value(nvalue:Number):Void {
_nvalue = nvalue;
}如果你有一對方法 - 一個getter和一個setter - 對同一個屬性,你只需要把[Inspectable] 放在它們之前。
[Inspectable] metatag允許你設定一些額外的資訊作為名稱/值的清單。你可以在Flash的說明文件內查詢[Inspectable] 的完整資訊,其中最重要的有下面三點:
* defaultvalue - 預設值是Flash使用的。這是組件第一次被拖曳到舞
代码:
[Inspectable(defaultvalue=10)]* type - 值的型別。這與使用者如何與Flash內的參數值互動有關。預設值是Default,運許使用者在組件檢測器中鍵入一個值。你也可以指定像是Boolean(讓使用者選擇true或false)和Color(出現顏色選擇器)。
代码:
[Inspectable(type=Color)]* enumeration - 使用者可以選取的值的清單。這通常使用於陣列。列舉選項應該是用逗號分開的清單。
代码:
[Inspectable(type=Array, enumeration="a,b,c,d,e,f,g")]
當你更新了(新增、移除)類別的參數,或編輯了[Inspectable] metatag,你應該開啟組鍵定義對話框,再一次點擊OK,讓Flash把資訊更新。
處理尺寸縮放 (Resizing)
設定組件時,處理尺寸縮放式是不可免的。預設情況下,當你縮放組件實體大小時,不論是編輯時或播放時_width和_height屬性改變 - Flash只是很簡單的縮放組件。通常這種縮放方式不是你想要的。舉例來說,下面的文章中,你將建立一個簡單的卷軸組件。卷軸由許多部分組成,包含上、下捲動的按鈕,scroll track和scroll thumb bar。如果你調整捲軸的尺寸,你應該不希望上下捲動的按鈕被縮放,它們應該維持同樣的尺寸。而scroll track應該縮放到填滿上下捲動按鈕中間的整個區域。 圖1比較了剛剛講的兩個狀況。
圖 1: 兩個捲軸都縮放到150 pixels高 。然而,左邊捲軸的上下捲動按紐沒有變形。右邊卷軸的上下捲動鈕只是隨捲軸尺寸縮放。
因此,你應該想要更聰明的處理縮放。總共有兩種縮放的方式可能發生 - 編輯時縮放(調整屬性檢測器中的值),播放時縮放(調整組件實體的屬性)。這兩種方式的處理方式不同,所以我們分開來看。
我們先看,編輯時的縮放。編輯時的縮放其實只是影響live preview的外觀,並不是真正的和播放時的外觀相同。 但是live preview的外觀一樣的重要。如果你建立編輯時的組件實體,你會想要看到你對組鍵做的改變。當你在屬性檢視器中設定了寬和高的值,Flash只有縮放movie clip或組件的實體。為了偵測和處理縮放,你應該在組件類別中,實做一個 setSize()方法。和我前面提到的幾個方法不同(init()、 draw()等等),setSize()方法的名稱寫在Flash的核心當中。在編輯時期組件實體的尺寸發生改變時,Flash將會自動呼叫組件類別的setSize()方法,並傳送兩個參數給此方法 - 第一個是新的寬度,第二個是新的高度。在你的setSize()方法中,你應該要下面兩件事:
* 將實體的縮放(scaling)設定為100。
* 呼叫arrange(),可能的話呼叫draw()方法。
通常我也在組件類別內建立__width和__height屬性(兩個底線是為了和內建的_width和_height 屬性作出區隔)。我使用者兩個屬性儲存組件實體的正確尺寸。當你設定實體的縮放比例到100%g時,你就會遺失設定_width and _height(一個底線)而產生的寬、高值。所以我建議你把第一個值設定給__width a第二個值設定給__height (都是兩個底線)。 當其他方法,如:draw()和arrange()需要使用長、寬做運算時,就用__width和__height。這樣你就會比較清楚後面示範的組件如何運作。
你可以了解setSize()方法的實作應該像下面這樣:
代码:
private function setSize(nW:Number, nH:Number):Void {
_xscale = 100; _yscale = 100;
if(nW != null) { __width = nW;
}
if(nH != null) { __height = nH;
} arrange();
}你也應該在類別中的init()方法內,設定縮放比例與__width和__height屬性。在本例當中,你將會設定_width的值到__width,_height的值到__height。所以你在你把縮放比例設定到100%之前,要確定已經做了正確的傳值。舉例來說:
代码:
private function init():Void { __width = _width; __height = _height; _xscale = 100; _yscale = 100; mcBoundingBox._visible = false; mcBoundingBox._width = 0; mcBoundingBox._height = 0;}下一件應該處理的就是播放時的尺寸縮放。如果你已經使用過任何v2 組件,你就會注意到它們縮放時不使用超類別 MovieClip的_width和_height屬性。如果你嘗試使用_width和_height屬性對組件的實體進行縮放,那麼得到的結果不是我們想要的。v2的寬、高屬性被定義為getter和setter方法,如此一來組件能夠聰明的處理縮放。我建議你在自訂的組件中也這樣處理尺寸縮放。
我建議寬度、高度的getter和setter可以這樣實做:
* setter方法裡呼叫setSize()。
* getter方法回傳__width或__height的值。
下面是一組getter和setter方法的例子:
代码:
public function set height(nHeight:Number):Void { setSize(null, nHeight); }
public function get height():Number { return __height; }處理尺寸縮放還要注意到,我們在其他方法要使用__width and __height(都是兩個底線)來計算圖形排列與繪製。如果你使用內建的_width and _height(一個底線),那麼就只會排列、繪製成預設大小。
分派事件 (Dispatching Events)
組件應該要有分派事件的能力。如果你還不熟悉v2組件的listener model,你應該先閱讀一下說明文件。以下是listener model的一些要點。
你可以使用addEventListener()方法增加一個物件作為v2組件的listener。當組件發生一個事件時,所有註冊過要接收此類型事件的listener物件都惠接收到訊息。Flash接下來會呼叫listener物件中和事件同名的方法。舉例來說,如果你有一個Button實體,你可以註冊一個listener物件來處理事件。下面是程式碼:
代码:
var oListener:Object = new Object();
oListener.click = function(oEvent:Object):Void {
trace(oEvent.target + " was clicked");
};
cbSubmitButton.addEventListener("click", oListener);讓你的組件和v2組件相同的派遣事件到一個listener其實很容易。在mx.events套件(Flash內建的類別套件)你可以找到EventDispatcher類別。你可以在你的組件類別內呼叫此類別的靜態方法initialize(),讓你的組件能夠註冊listener和派遣任務。initialize()方法需要一個參數,參照你想要讓它有事件派遣功能的物件。在這邊的例子當中,這個參數的值是this。我通常建議你在你的類別中的init()方法中,呼叫mx.events.EventDispatcher.initialize()方法。下面是一個例子,(請參考粗體部分):
代码:
private function init():Void { __width = _width; __height = _height; _xscale = 100; _yscale = 100; mx.events.EventDispatcher.initialize(this); mcBoundingBox._visible = false; mcBoundingBox._width = 0; mcBoundingBox._height = 0;}
要派遣一個任務,你可以使用dispatchEvent()方法,如此一來你的類別就由EventDispatcher”繼承”(並不是真的繼承)。你唯一要確認的就是把dispatchEvent()宣告為一個類別成員,如同下面的程式碼:
代码:
private var dispatchEvent:Function;這樣只是讓類別知道有這個方法存在。如果你此類別內沒有程式碼,編譯時Flash就會出現錯誤訊息。
dispatchEvent()方法需要一個參數 - 一個至少有兩個參數type和target的物件。type 屬性應該是指定事件名稱的字串。target屬性應該欲派遣事件的物件的參照。大部分的情況下,應該是this。下面就是派遣事件的例子:
代码:
dispatchEvent({type: "click", target: this});不用擔心看不太懂上面的討論。只要你開始做組件,你就會清楚了。
匯出compiled clip
當你建立了自己的組件元件和類別,你會想要把組件壓縮輸出為.swc檔案。.swc檔其實是zip格式的壓縮檔,裡面有所有組件需要的元素,包含live preview。當你輸出了.swc檔,把它放到正確的目錄下之後,組件就會在Flash內出現。如此一來你就可以在其他的Flash檔案內使用自訂的組件。你也可以再把它包裝成.mxp,方便傳送給其他人使用。
匯出一個.swc檔案也可簡單。你只要選取元件庫裡面所有的組件movie clip,按滑鼠右鍵/command-點選在選單上選擇輸出SWC。Flash將會問你要把檔案儲存在哪。選擇好路徑之後,.swc檔就會儲存了。
為了增加組件到你的組件面板內,你必須把.swc檔案複製到正確的目錄。在Windows XP平台上,路徑應該是C:\Documents and Settings\[使用者名稱]\Local Settings\Application Data\Macromedia\Flash MX 2004\en\Configuration\Components。我沒有Mac所以不清楚在Mac上的路經。當你把檔案放到該目錄下之後,你可以重新讀取組件面板。開啟組件面板的選單,選擇重新載入就可以看到自訂的組件出現在清單內了。
注意:你應該把.swc檔案儲存在Component目錄下的子目錄中。
為了把組件包裝為.mxp檔案,你必須要安裝Extension Manager。你需要建立一個.mxi檔案。.mxi檔案是一個XML格式的檔案。下面是.mxi檔的例子:
代码:
<macromedia-extension name="com.person13.SampleScrollBar" version="1.0" type="flashcomponent">
<!-- 宣告作者 -->
<author name="Joey Lott" />
<!-- 需求/相容的產品 -->
<products>
<product name="Flash" version="7" primary="true" />
</products>
<!-- 宣告擴充功能 -->
<description>
<![CDATA[
Window component.
]]>
</description>
<!-- 宣告擴充功能出現的地方 -->
<ui-access>
<![CDATA[
Components panel.
]]>
</ui-access>
<!-- 宣告擴充功能包含的檔案。這個.mxi檔案必須和.swc檔案存在同一個目錄下。-->
<files>
<file name="SampleScrollBar.swc" destination="$flash/Components/" />
</files>
</macromedia-extension>你可以打開Extension Manager來打包組件。選擇檔案>包裝擴充功能。在對話框選擇.mxi檔案,點選確定。然後設定.mxp的要儲存的檔名和路徑,匯出.mxp。你可以把.mxp檔案給所有有Extension Manager的人,他們要安裝你的組件只要點選.mxp就可以安裝了。
建立一個簡單的組件
讀完了這麼多概念性的東西,我們來實做看看吧。這個練習中,你將會建立一個簡單的捲軸組件。這個卷軸組件只包含了簡單的功能,你可以自己再增加更多功能。
1. 下載SampleScrollBar.zip。http://www.person13.com/articles/co...leScrollBar.zip
2. 把.zip檔案解壓縮之後,應該有下面的內容:
/StarterFiles
- SampleScrollBar_starter.fla
- com/person13/SampleScrollBar.as
/CompletedFiles
- SampleScrollBar.fla
- com.person13/SampleScrollBar.as
StarterFiles目錄包含了所有開始練習時的檔案。.fla檔案包含了所有的圖像。CompletedFiles目錄下提供了完成的檔案。
3. 開啟StarterFiles/SampleScrollBar_starter.fla,然後開啟文件的元件庫。
4. 在元件庫內,你可以看到一些movie clip元件。ScrollUp、ScrollDown、ScrollTrack和ScrollThumb已經設定好匯出和連結的識別名稱。ScrollBar則還沒做輸出設定。所以開啟元件連結設定,選擇匯出給ActionScript使用。識別名稱設定為ScrollBar。AS 2.0類別設定為com.person13.SampleScrollBar。
5. 在編輯模式中開啟ScrollBar元件。你可以看到兩個圖層和幾個keyframe已經被建立。請在keyframe中增加stop()。
6. 拖曳BoundingBox的實體到Assets圖層的第一個影格。把實體名稱命名為mcBoundingBox,把尺寸設定為15pixel寬100pixel高,位置設定到0,0。
7. 在Assets圖層的第二個影格,增加ScrollUp、ScrollDown、ScrollTrack和ScrollThumb的實體。
8. 儲存.fla檔案,然後開啟com/person13/SampleScrollBar.as。
9. SampleScrollBar.as特別留下部分的空白。請把下面的程式碼加到類別內:
__________________
代码:
class com.person13.SampleScrollBar extends MovieClip {
// 元件內的BoundingBox實體是在編輯時建立的。
private var mcBoundingBox:MovieClip;
// 其他元件內的實體你必須由程式來建立。
private var _mcScrollUp:MovieClip; private var _mcScrollTrack:MovieClip; private var _mcScrollDown:MovieClip; private var _mcScrollThumb:MovieClip;
// 讓setInterval()和clearInterval()使用的間隔識別 (interval identifier)。
private var _nInterval:Number;
// 位移。與你在scroll thumb bar上點擊的位置有關。
private var _nOffset:Number;
// __width和__height屬性儲存實體的尺寸
private var __width:Number; private var __height:Number;
// 先前的scroll值。此變數用來確認當組件的scroll值變化時,才派遣事件。
private var _nPrevScroll:Number;
// scroll值的最大和最小值。預設值是0到100。 private var _nMax:Number = 100; private var _nMin:Number = 0;
// scroll thumb bar的位置。
private var _nScrollPosition:Number = 0;
// 由EventDispatcher增加的dispatchEvent()方法。
private var dispatchEvent:Function;
// min和max的getter和setter方法。
[Inspectable(defaultvalue=0)] public function set min(nMin:Number):Void { _nMin = nMin; }
public function get min():Number { return _nMin; }
[Inspectable(defaultvalue=100)] public function set max(nMax:Number):Void { _nMax = nMax; }
public function get max():Number { return _nMax; }
// scrollPosition的getter和setter方法。當scrollPosition被設定,指定這個值到私有的屬性,然後呼叫arrage()。
// 當這個植要被取得,用thumb bar的_y和min、max值作運算。
[Inspectable(defaultvalue=0,type=Number)] public function set scrollPosition(nScrollPosition:Number):Void { _nScrollPosition = nScrollPosition; arrange(); }
public function get scrollPosition():Number { var nVal:Number = (_mcScrollThumb._y - _mcScrollTrack._y) / (_mcScrollTrack._height - _mcScrollThumb._height) * (_nMax - _nMin) + _nMin;
return Math.round(nVal); }
// 高度的getter和setter方法。不需要定義寬度,因為這只是個簡單的直向捲軸。
public function set height(nHeight:Number):Void { setSize(null, nHeight); }
public function get height():Number { return __height; }
// 在編輯時期縮放實體尺寸時,setSize()方法會自動被呼叫。
public function setSize(nW:Number, nH:Number):Void { _xscale = 100; _yscale = 100; __width = nW; __height = nH; arrange(); }
// 建構式。
function SampleScrollBar() { init(); createChildren(); arrange(); }
// 本文提到的init()方法
private function init():Void { __width = _width; __height = _height; _xscale = 100; _yscale = 100; mx.events.EventDispatcher.initialize(this); mcBoundingBox._visible = false; mcBoundingBox._width = 0; mcBoundingBox._height = 0; }
// createChilnden()方法設定上下捲動按鈕、scroll track和scroll thumb bar。
// 雖然你也可以在類別裡定義,但是這個例子我們在createChildren()方法中指定
// onPress()、onRelease()和onReleaseOutside()方法。
private function createChildren():Void { attachMovie("ScrollUp", "_mcScrollUp", getNextHighestDepth()); attachMovie("ScrollTrack", "_mcScrollTrack", getNextHighestDepth()); attachMovie("ScrollDown", "_mcScrollDown", getNextHighestDepth()); attachMovie("ScrollThumb", "_mcScrollThumb", getNextHighestDepth()); _mcScrollThumb.onPress = function():Void { this._parent._nOffset = this._ymouse; this._parent._nInterval = setInterval(this._parent, "scroll", 10); }; _mcScrollThumb.onRelease = function():Void { clearInterval(this._parent._nInterval); }; _mcScrollThumb.onReleaseOutside = _mcScrollThumb.onRelease; _mcScrollUp.onPress = function():Void { this._parent._nInterval = setInterval(this._parent, "nudge", 10, -1); }; _mcScrollUp.onRelease = function():Void { clearInterval(this._parent._nInterval); }; _mcScrollUp.onReleaseOutside = _mcScrollUp.onRelease; _mcScrollDown.onPress = function():Void { this._parent._nInterval = setInterval(this._parent, "nudge", 10, 1); }; _mcScrollDown.onRelease = function():Void { clearInterval(this._parent._nInterval); }; _mcScrollDown.onReleaseOutside = _mcScrollDown.onRelease; }
// 排列所有的元素。當實體建立和尺寸縮放時,這個方法會被呼叫。
private function arrange():Void {
// 設定scroll track的高度,使它的高度等於實體高度(由__height取得)
// 減去上下按鈕的高度。 _mcScrollTrack._height = __height - _mcScrollUp._height - _mcScrollDown._height;
// 把scroll track的位置調整到向上捲動的按鈕下面。 _mcScrollTrack._y = _mcScrollUp._height;
// 把向下捲動的按鈕的位置調整到scroll track之下。 _mcScrollDown._y = _mcScrollTrack._y + _mcScrollTrack._height;
// 把scroll thumb bar放在scroll track內(向又調整1pixel)。 _mcScrollThumb._x = 1;
// 以_nScrollPosition為基礎決定scroll thumb bar的垂直的位置
var nY:Number = ((_nScrollPosition - _nMin)/(_nMax - _nMin)) * (_mcScrollDown._y - _mcScrollThumb._height); if(nY > _mcScrollDown._y - _mcScrollThumb._height) { nY = _mcScrollDown._y - _mcScrollThumb._height; } else if(nY < _mcScrollTrack._y) { nY = _mcScrollTrack._y; } _mcScrollThumb._y = nY; }
// 當thumb bar被使用者拖曳時,此方法被不斷呼叫。
This method is called at an interval when the thumb bar is dragged by the user.
private function scroll():Void {
// 以_ymouse的位移決定thumb bar的垂直位置。
// 同時也計算最大和最小值的範圍。如果滑鼠的值超過了最大或最小值,就把數值鎖定,讓thumb bar不跑到scroll track之外。 var nY:Number = _ymouse - _nOffset; var nUpper:Number = _mcScrollTrack._y; var nLower:Number = _mcScrollDown._y - _mcScrollThumb._height; if(nY > nUpper && nY < nLower) { _mcScrollThumb._y = _ymouse - _nOffset; } else if(nY < nUpper) { _mcScrollThumb._y = nUpper; } else if(nY > nLower) { _mcScrollThumb._y = nLower; }
// 使用自訂的dispatchScrollEvent()派遣事件。(在後面定義。)
dispatchScrollEvent(); updateAfterEvent(); }
// 當上下按鈕被按下時,這個方法被呼叫。功能和scroll()方法很接近。
// 你可以看看scroll()方法的註解了解更細節的部份。
private function nudge(nIncrement:Number):Void { var nUpper:Number = _mcScrollTrack._y; var nLower:Number = _mcScrollDown._y - _mcScrollThumb._height; _mcScrollThumb._y += nIncrement; if(_mcScrollThumb._y < nUpper) { _mcScrollThumb._y = nUpper; } else if(_mcScrollThumb._y > nLower) { _mcScrollThumb._y = nLower; } dispatchScrollEvent(); updateAfterEvent() }
// 如果目前的值和先前不同,派遣一個scroll事件。
private function dispatchScrollEvent():Void { if(_mcScrollThumb._y != _nPrevScroll) { dispatchEvent({type: "scroll", target: this}); _nPrevScroll = _mcScrollThumb._y; } }
}10. 儲存.as檔,並回到.fla。
11. 選擇元件庫內的ScrollBar元件,然後開啟元件定義對話框。
12. 把AS 2.0類別設定為com.person13.SampleScrollBar選擇確定。
13. 選取ScrollBar元件,點選匯出SWC選項。匯出檔案到Components/UI Components目錄下。就像之前說明的那樣。
14. 開啟一個新的.fla文件。
15. 開啟組建面板,並重新載入。ScrollBar元件應該就會出現在面板中。
16. 從組件面板拖曳ScrollBar的實體到主時間軸的舞台上。把實體的名稱設定為csbScroller。
14. 開啟元件檢測器面板。你應該可以看到max、min和scrollPosition屬性。設定他們的值為200、-200和100。
15. 使用屬性檢測器把組件的實體的高度縮放到200pixel。
16. 在主時間軸增加新的圖層,增加下面的程式碼到此時間軸的keyframe裡:
代码:
var oListener:Object = new Object();
oListener.scroll = function(oEvent:Object):Void {
trace(oEvent.target.scrollPosition);
};
csbScroller.addEventListener("scroll", oListener);17. 測試影片。當你捲動捲軸時,應該可以看到scrollPosition的值顯示在輸出面板。
結論
組件是強大而又令人疑惑的議題。希望本篇文章能夠幫助你開始寫自己的組件。本文並不打算完整的討論這個議題。有任何的意見或指正,請寫信給我,謝謝您的閱讀。
李易修 ( www.lis186.com ) 譯
別讓建立自訂組件嚇到你。雖然組件可能很複雜,事實上它們只是比較特別的movie clip。不論你知不知道如何製作movie clip,你都可以製作組件。你唯一需要了解的就是ActionScript 2.0類別怎麼寫。如果你還不知道如何撰寫ActionScript 2.0類別,你可以先到http://www.person13.com/articles,?..t入門系列文章。
本文將探討的議題有:
* 組件的好處。
* 建立組件的影片片段 (component movie clip)。
* 撰寫基本的組件類別 (component class)。
* 連結組件類別與影片片段。
* 匯出壓縮的影片片段 (compiled clip)。
你可能已經發現上面列出的議題,並不包含如何擴充v2 component framework。我不在本文中探討V2 component有幾個原因。第一我認為重頭開始製作組件,應該會比擴充Macromedia的V2 component更容易了解組件的架構。除了V2 framework提供了style和focus management等幾個不錯的功能,我找不到v2 framework太多的優點,值得增加這麼多的檔案容量到.swf。舉例來說,如果你增加了ProgressBar組件到空的Flash文件內,並輸出,檔案大小已經是27KB。如果你擴充了v2 framework,你可以確定檔案大小一定大於Macromedia的ProgressBar。
如果你你想要擴充v2 framework,這篇文章也有一些你想知道的基本概念。當你了解了這些之後,你就已經準備好如何利用v2 framework了。
組件的好處
在你開始學習建立組件之前,你很可能想先了解組件的優點。雖然組件只是特殊的movie clip,不過組件也可以很強大。這是一個全體大於部份的總和的例子。
就像Flash內建的基本UI component。你也可以建立一個自訂的combobox或是按鈕控制項,需要的時候就可以直接使用。你也可以先繪製圖形,然後在主時間軸寫大量ActionScript程式碼,完成類似的工作。但是我確定把組件拖曳到場景裡、設定參數,一定簡單的多。這個簡單的例子說明了許多組件的好處。組件包含了可再用的功能,並以某種形式封裝,讓你只要把組件拖曳到場景上就可以利用了。此外,組件讓你使用圖形使用者介面設定參數 (Component Inspector panel, 組件檢測器) 或使用API。這代表你可以使用ActionScript控制組件強大的功能,也可以使用組件檢測器方便的設定參數。
不只有組件能封裝功能,但它們可以讓功能更容易的散佈出去。如果你想要讓別人使用你製作的組件,你要做的只有包裝、傳送它。只要點幾下滑鼠,組件就會安裝好了。此外,如果你把組件包裝成.swc檔,程式碼相對的就受到比較好的保護。(雖然有一些反組譯程式以樣可以取得你的ActionScript程式碼。)
建立組件的影片片段 (Component Movie Clip)
除了某些例外情況外,你必須在runtime附加 (attach)或載入所有的圖像到組件內。這代表你要用ActionScript處理所有的事情。因此,組件的影片片段(component movie clip)真的很簡單。然而, 有幾件事情你必須要記得:
* 組件只會顯示邊界內的圖像,而邊界是在編輯時定義在movie clip內的。這聽起來很奇怪。這代表如果你在編輯時,沒有在component movie clip內定義圖像,那麼附加或載入的圖像都不會被顯示出來。解決的方法就是在movie clip的第一個影格內,定義一個方形的影片片段實體 (rectangular movie clip instance)。我通常稱這個實體為mcBoundingBox。mcBoundingBox應該能夠符合所有組件圖像的尺寸。
* 為了能夠正確的輸出.swc檔案(本文稍後將介紹如何製作),組件元件(component symbol)內需要包含所有由程式碼附加的元件。此外,其他元件不會被匯出到.swc內。因此,因此,我建議在component movie clip的第二個影格,加上所有由程式碼附加的實體。
* 你的component movie clip元件將會有兩個影格 - 第一個影格包含mcBoundingBox實體。第二個影格包含所有想要附加的元件。請記得在第一個影格,加上stop()。
建立組件的類別 (Component Class)
組件至少包含一個影片片段元件和一個相關的ActionScript類別。你應該已經知道如何建立影片片段元件,因此本篇文章我門只探討如何建立ActionScript類別。如果你已經知道如何撰寫基本的ActionScript 2.0類別,這個部分將會相當的簡單。
組件類別應該由MovieClip類別擴充。由MovieClip類別擴充組件類別,可以讓組件繼承MovieClip類別中所有的屬性與方法。這代表你可以使用ActionScript控制組件的位置、顯示與否和透明度等等。這也代表你可以在類別內使用createEmptyMovieClip()和 attachMovie()在組件內增加巢狀的元素。舉例來說,你可能想要為你的組件建立一個基本的類別,以提供一項通用的功能。這個類別應該由MovieClip擴充,其他的類別則應該由此類別擴充。
元件類別有幾個特殊的方法可以(需要)實做。我們會一一說明這些方法。首先,我們先建立一個基本的類別作為例子。
代码:
class com.person13.SampleComponent extends MovieClip {
// 為了讓程式碼可以參照,你必須宣告類別成員。
// 在這個例子當中,mcBoundingBox是在組件元件中,做為邊界的movie clip的名稱。
private var mcBoundingBox:MovieClip;
function SampleComponent() {
// 建構式能夠呼叫其他方法,避免直接再建構式內寫一堆程式碼。
// 它能夠幫助你組織程式碼。你將會看到建構式能夠帶來的好處。
init();
}
private function init():Void {
// 通常你想要設定邊界方塊為不可見的,尺寸也設定為0。
// 邊界方塊在編輯時的尺寸代表影片播放時,組件顯示的範圍,
// 但組件在播放時可以隱藏。
mcBoundingBox._visible = false;
mcBoundingBox._width = 0;
mcBoundingBox._height = 0;
}
}
前面的類別是最基本的組件類別。你應該確定類別是由MovieClip擴充,並且隱藏了邊界方塊的實體。這些程式碼並不長,我只是想讓你 a)知道不需要寫多餘程式碼 b)了解每個部分的程式做了些什麼事情。
就像上面程式碼的註解,我建議你在建構式內呼叫其他方法,而不要在建構式內加入太多功能。我通常實做了下面的幾個方法,並在建構式中呼叫:
* init() - 此方法包含初始化的所需要的程式碼。我通常把實體的縮放比例設定為100%,理由容後再述。另外,我也在這裡隱藏邊界方塊,並初始化此類別,讓它能夠派遣 (dispatch)事件(後面會做解釋)。
* createChildren() - 用來附加或建立所有movie clip和text field等等的方法。 通常包含attachMovie()和/或createEmptyMovieClip()。
* draw() - 此方法處理所有需要用程式繪圖的部份。並不是所有的組件都需要畫什麼東西。
* arrange() - 佈置所有的圖像到正確的位置。通常組件存在之後, arrange()方法會被呼叫很多次。舉例來說,每次組件的大小被調整,我們通常需要調整組件內元素的位置。
後面你將會看到這些方法的實做範例。
連結組件類別和影片元素
你定義了基本的影片片段元件和元件類別之後,接下來就應該把這兩個部分連結起來。當一個movie clip的實體被建立 - 不論是拖曳實體到舞台上或使用程式碼附加到舞台上 - Flash通常把此元件連結到MovieClip類別。但你想要讓Flash把元件的連接到你的自訂類別,如此這個實體才能存取你在類別內建立的功能。
你可以修改元件的連結設定 (linkage settings)中ActionScript 2.0類別,以設定movie clip所連結的類別。 要開啟movie clip的連結設定,可以在元件庫內的元件上按滑鼠右鍵/command-click,選擇連結設定。連結設定中你需要設定:
* 勾選匯出給ActionScript使用。
* 設定元件的識別名稱。
* 在AS 2.0類別欄位內設定類別。 你應該提供完整的類別名稱 (fully-qualified class name)。這代表如果類別在com.person13套件內,你就需要包含套件名稱。
你設定好元件連結的類別之後。當你建立了元件的實體,Flash會自動讓實體連結到指定的類別,取代預設的MovieClip。
增加參數 (Parameters)
雖然你可能想建立能由API控制的組件,但是在大多數的狀況下你也會想讓元件的實體能夠由組件檢測器設定參數 - 讓不懂AcgtionScript的人也能使用它。這也是組件的好處之一。
如果你利用Flash MX建立過組件,你應該記得你是在組件定義對話框中定義參數的。 在Flash MX 2004中,這個對話框仍然存在,但是已經不建議使用。 當你在Flash MX 2004中使用ActionbScript 2.0類別建立組件,你應該在類別內使用特殊的metatag定義參數。 使用metatag定義參數的方式比之前好太多了。最大的有優點就是效率比起之前愚蠢的對話框好多了。
[Inspectable] metata告訴Flash這是為組件設定的參數。如果你在類別內使用了[Inspectable] metatag在任何屬性之前(包含getter和setter方法),這個屬性就會自動變為參數。除了getter和setter之外,我通常不主張把屬性定義為公開的。所以,下面的例子,我將只使用getter和setter方法。但是你也可以把 [Inspectable] 放在公開的屬性前,這樣一樣能夠運作。
下面的例子告訴你,[Inspectable] 標前能夠被放置在getter或setter方法前,使其成為一個參數。
代码:
[Inspectable]
public function set value(nvalue:Number):Void {
_nvalue = nvalue;
}如果你有一對方法 - 一個getter和一個setter - 對同一個屬性,你只需要把[Inspectable] 放在它們之前。
[Inspectable] metatag允許你設定一些額外的資訊作為名稱/值的清單。你可以在Flash的說明文件內查詢[Inspectable] 的完整資訊,其中最重要的有下面三點:
* defaultvalue - 預設值是Flash使用的。這是組件第一次被拖曳到舞
代码:
[Inspectable(defaultvalue=10)]* type - 值的型別。這與使用者如何與Flash內的參數值互動有關。預設值是Default,運許使用者在組件檢測器中鍵入一個值。你也可以指定像是Boolean(讓使用者選擇true或false)和Color(出現顏色選擇器)。
代码:
[Inspectable(type=Color)]* enumeration - 使用者可以選取的值的清單。這通常使用於陣列。列舉選項應該是用逗號分開的清單。
代码:
[Inspectable(type=Array, enumeration="a,b,c,d,e,f,g")]
當你更新了(新增、移除)類別的參數,或編輯了[Inspectable] metatag,你應該開啟組鍵定義對話框,再一次點擊OK,讓Flash把資訊更新。
處理尺寸縮放 (Resizing)
設定組件時,處理尺寸縮放式是不可免的。預設情況下,當你縮放組件實體大小時,不論是編輯時或播放時_width和_height屬性改變 - Flash只是很簡單的縮放組件。通常這種縮放方式不是你想要的。舉例來說,下面的文章中,你將建立一個簡單的卷軸組件。卷軸由許多部分組成,包含上、下捲動的按鈕,scroll track和scroll thumb bar。如果你調整捲軸的尺寸,你應該不希望上下捲動的按鈕被縮放,它們應該維持同樣的尺寸。而scroll track應該縮放到填滿上下捲動按鈕中間的整個區域。 圖1比較了剛剛講的兩個狀況。
圖 1: 兩個捲軸都縮放到150 pixels高 。然而,左邊捲軸的上下捲動按紐沒有變形。右邊卷軸的上下捲動鈕只是隨捲軸尺寸縮放。
因此,你應該想要更聰明的處理縮放。總共有兩種縮放的方式可能發生 - 編輯時縮放(調整屬性檢測器中的值),播放時縮放(調整組件實體的屬性)。這兩種方式的處理方式不同,所以我們分開來看。
我們先看,編輯時的縮放。編輯時的縮放其實只是影響live preview的外觀,並不是真正的和播放時的外觀相同。 但是live preview的外觀一樣的重要。如果你建立編輯時的組件實體,你會想要看到你對組鍵做的改變。當你在屬性檢視器中設定了寬和高的值,Flash只有縮放movie clip或組件的實體。為了偵測和處理縮放,你應該在組件類別中,實做一個 setSize()方法。和我前面提到的幾個方法不同(init()、 draw()等等),setSize()方法的名稱寫在Flash的核心當中。在編輯時期組件實體的尺寸發生改變時,Flash將會自動呼叫組件類別的setSize()方法,並傳送兩個參數給此方法 - 第一個是新的寬度,第二個是新的高度。在你的setSize()方法中,你應該要下面兩件事:
* 將實體的縮放(scaling)設定為100。
* 呼叫arrange(),可能的話呼叫draw()方法。
通常我也在組件類別內建立__width和__height屬性(兩個底線是為了和內建的_width和_height 屬性作出區隔)。我使用者兩個屬性儲存組件實體的正確尺寸。當你設定實體的縮放比例到100%g時,你就會遺失設定_width and _height(一個底線)而產生的寬、高值。所以我建議你把第一個值設定給__width a第二個值設定給__height (都是兩個底線)。 當其他方法,如:draw()和arrange()需要使用長、寬做運算時,就用__width和__height。這樣你就會比較清楚後面示範的組件如何運作。
你可以了解setSize()方法的實作應該像下面這樣:
代码:
private function setSize(nW:Number, nH:Number):Void {
_xscale = 100; _yscale = 100;
if(nW != null) { __width = nW;
}
if(nH != null) { __height = nH;
} arrange();
}你也應該在類別中的init()方法內,設定縮放比例與__width和__height屬性。在本例當中,你將會設定_width的值到__width,_height的值到__height。所以你在你把縮放比例設定到100%之前,要確定已經做了正確的傳值。舉例來說:
代码:
private function init():Void { __width = _width; __height = _height; _xscale = 100; _yscale = 100; mcBoundingBox._visible = false; mcBoundingBox._width = 0; mcBoundingBox._height = 0;}下一件應該處理的就是播放時的尺寸縮放。如果你已經使用過任何v2 組件,你就會注意到它們縮放時不使用超類別 MovieClip的_width和_height屬性。如果你嘗試使用_width和_height屬性對組件的實體進行縮放,那麼得到的結果不是我們想要的。v2的寬、高屬性被定義為getter和setter方法,如此一來組件能夠聰明的處理縮放。我建議你在自訂的組件中也這樣處理尺寸縮放。
我建議寬度、高度的getter和setter可以這樣實做:
* setter方法裡呼叫setSize()。
* getter方法回傳__width或__height的值。
下面是一組getter和setter方法的例子:
代码:
public function set height(nHeight:Number):Void { setSize(null, nHeight); }
public function get height():Number { return __height; }處理尺寸縮放還要注意到,我們在其他方法要使用__width and __height(都是兩個底線)來計算圖形排列與繪製。如果你使用內建的_width and _height(一個底線),那麼就只會排列、繪製成預設大小。
分派事件 (Dispatching Events)
組件應該要有分派事件的能力。如果你還不熟悉v2組件的listener model,你應該先閱讀一下說明文件。以下是listener model的一些要點。
你可以使用addEventListener()方法增加一個物件作為v2組件的listener。當組件發生一個事件時,所有註冊過要接收此類型事件的listener物件都惠接收到訊息。Flash接下來會呼叫listener物件中和事件同名的方法。舉例來說,如果你有一個Button實體,你可以註冊一個listener物件來處理事件。下面是程式碼:
代码:
var oListener:Object = new Object();
oListener.click = function(oEvent:Object):Void {
trace(oEvent.target + " was clicked");
};
cbSubmitButton.addEventListener("click", oListener);讓你的組件和v2組件相同的派遣事件到一個listener其實很容易。在mx.events套件(Flash內建的類別套件)你可以找到EventDispatcher類別。你可以在你的組件類別內呼叫此類別的靜態方法initialize(),讓你的組件能夠註冊listener和派遣任務。initialize()方法需要一個參數,參照你想要讓它有事件派遣功能的物件。在這邊的例子當中,這個參數的值是this。我通常建議你在你的類別中的init()方法中,呼叫mx.events.EventDispatcher.initialize()方法。下面是一個例子,(請參考粗體部分):
代码:
private function init():Void { __width = _width; __height = _height; _xscale = 100; _yscale = 100; mx.events.EventDispatcher.initialize(this); mcBoundingBox._visible = false; mcBoundingBox._width = 0; mcBoundingBox._height = 0;}
要派遣一個任務,你可以使用dispatchEvent()方法,如此一來你的類別就由EventDispatcher”繼承”(並不是真的繼承)。你唯一要確認的就是把dispatchEvent()宣告為一個類別成員,如同下面的程式碼:
代码:
private var dispatchEvent:Function;這樣只是讓類別知道有這個方法存在。如果你此類別內沒有程式碼,編譯時Flash就會出現錯誤訊息。
dispatchEvent()方法需要一個參數 - 一個至少有兩個參數type和target的物件。type 屬性應該是指定事件名稱的字串。target屬性應該欲派遣事件的物件的參照。大部分的情況下,應該是this。下面就是派遣事件的例子:
代码:
dispatchEvent({type: "click", target: this});不用擔心看不太懂上面的討論。只要你開始做組件,你就會清楚了。
匯出compiled clip
當你建立了自己的組件元件和類別,你會想要把組件壓縮輸出為.swc檔案。.swc檔其實是zip格式的壓縮檔,裡面有所有組件需要的元素,包含live preview。當你輸出了.swc檔,把它放到正確的目錄下之後,組件就會在Flash內出現。如此一來你就可以在其他的Flash檔案內使用自訂的組件。你也可以再把它包裝成.mxp,方便傳送給其他人使用。
匯出一個.swc檔案也可簡單。你只要選取元件庫裡面所有的組件movie clip,按滑鼠右鍵/command-點選在選單上選擇輸出SWC。Flash將會問你要把檔案儲存在哪。選擇好路徑之後,.swc檔就會儲存了。
為了增加組件到你的組件面板內,你必須把.swc檔案複製到正確的目錄。在Windows XP平台上,路徑應該是C:\Documents and Settings\[使用者名稱]\Local Settings\Application Data\Macromedia\Flash MX 2004\en\Configuration\Components。我沒有Mac所以不清楚在Mac上的路經。當你把檔案放到該目錄下之後,你可以重新讀取組件面板。開啟組件面板的選單,選擇重新載入就可以看到自訂的組件出現在清單內了。
注意:你應該把.swc檔案儲存在Component目錄下的子目錄中。
為了把組件包裝為.mxp檔案,你必須要安裝Extension Manager。你需要建立一個.mxi檔案。.mxi檔案是一個XML格式的檔案。下面是.mxi檔的例子:
代码:
<macromedia-extension name="com.person13.SampleScrollBar" version="1.0" type="flashcomponent">
<!-- 宣告作者 -->
<author name="Joey Lott" />
<!-- 需求/相容的產品 -->
<products>
<product name="Flash" version="7" primary="true" />
</products>
<!-- 宣告擴充功能 -->
<description>
<![CDATA[
Window component.
]]>
</description>
<!-- 宣告擴充功能出現的地方 -->
<ui-access>
<![CDATA[
Components panel.
]]>
</ui-access>
<!-- 宣告擴充功能包含的檔案。這個.mxi檔案必須和.swc檔案存在同一個目錄下。-->
<files>
<file name="SampleScrollBar.swc" destination="$flash/Components/" />
</files>
</macromedia-extension>你可以打開Extension Manager來打包組件。選擇檔案>包裝擴充功能。在對話框選擇.mxi檔案,點選確定。然後設定.mxp的要儲存的檔名和路徑,匯出.mxp。你可以把.mxp檔案給所有有Extension Manager的人,他們要安裝你的組件只要點選.mxp就可以安裝了。
建立一個簡單的組件
讀完了這麼多概念性的東西,我們來實做看看吧。這個練習中,你將會建立一個簡單的捲軸組件。這個卷軸組件只包含了簡單的功能,你可以自己再增加更多功能。
1. 下載SampleScrollBar.zip。http://www.person13.com/articles/co...leScrollBar.zip
2. 把.zip檔案解壓縮之後,應該有下面的內容:
/StarterFiles
- SampleScrollBar_starter.fla
- com/person13/SampleScrollBar.as
/CompletedFiles
- SampleScrollBar.fla
- com.person13/SampleScrollBar.as
StarterFiles目錄包含了所有開始練習時的檔案。.fla檔案包含了所有的圖像。CompletedFiles目錄下提供了完成的檔案。
3. 開啟StarterFiles/SampleScrollBar_starter.fla,然後開啟文件的元件庫。
4. 在元件庫內,你可以看到一些movie clip元件。ScrollUp、ScrollDown、ScrollTrack和ScrollThumb已經設定好匯出和連結的識別名稱。ScrollBar則還沒做輸出設定。所以開啟元件連結設定,選擇匯出給ActionScript使用。識別名稱設定為ScrollBar。AS 2.0類別設定為com.person13.SampleScrollBar。
5. 在編輯模式中開啟ScrollBar元件。你可以看到兩個圖層和幾個keyframe已經被建立。請在keyframe中增加stop()。
6. 拖曳BoundingBox的實體到Assets圖層的第一個影格。把實體名稱命名為mcBoundingBox,把尺寸設定為15pixel寬100pixel高,位置設定到0,0。
7. 在Assets圖層的第二個影格,增加ScrollUp、ScrollDown、ScrollTrack和ScrollThumb的實體。
8. 儲存.fla檔案,然後開啟com/person13/SampleScrollBar.as。
9. SampleScrollBar.as特別留下部分的空白。請把下面的程式碼加到類別內:
__________________
代码:
class com.person13.SampleScrollBar extends MovieClip {
// 元件內的BoundingBox實體是在編輯時建立的。
private var mcBoundingBox:MovieClip;
// 其他元件內的實體你必須由程式來建立。
private var _mcScrollUp:MovieClip; private var _mcScrollTrack:MovieClip; private var _mcScrollDown:MovieClip; private var _mcScrollThumb:MovieClip;
// 讓setInterval()和clearInterval()使用的間隔識別 (interval identifier)。
private var _nInterval:Number;
// 位移。與你在scroll thumb bar上點擊的位置有關。
private var _nOffset:Number;
// __width和__height屬性儲存實體的尺寸
private var __width:Number; private var __height:Number;
// 先前的scroll值。此變數用來確認當組件的scroll值變化時,才派遣事件。
private var _nPrevScroll:Number;
// scroll值的最大和最小值。預設值是0到100。 private var _nMax:Number = 100; private var _nMin:Number = 0;
// scroll thumb bar的位置。
private var _nScrollPosition:Number = 0;
// 由EventDispatcher增加的dispatchEvent()方法。
private var dispatchEvent:Function;
// min和max的getter和setter方法。
[Inspectable(defaultvalue=0)] public function set min(nMin:Number):Void { _nMin = nMin; }
public function get min():Number { return _nMin; }
[Inspectable(defaultvalue=100)] public function set max(nMax:Number):Void { _nMax = nMax; }
public function get max():Number { return _nMax; }
// scrollPosition的getter和setter方法。當scrollPosition被設定,指定這個值到私有的屬性,然後呼叫arrage()。
// 當這個植要被取得,用thumb bar的_y和min、max值作運算。
[Inspectable(defaultvalue=0,type=Number)] public function set scrollPosition(nScrollPosition:Number):Void { _nScrollPosition = nScrollPosition; arrange(); }
public function get scrollPosition():Number { var nVal:Number = (_mcScrollThumb._y - _mcScrollTrack._y) / (_mcScrollTrack._height - _mcScrollThumb._height) * (_nMax - _nMin) + _nMin;
return Math.round(nVal); }
// 高度的getter和setter方法。不需要定義寬度,因為這只是個簡單的直向捲軸。
public function set height(nHeight:Number):Void { setSize(null, nHeight); }
public function get height():Number { return __height; }
// 在編輯時期縮放實體尺寸時,setSize()方法會自動被呼叫。
public function setSize(nW:Number, nH:Number):Void { _xscale = 100; _yscale = 100; __width = nW; __height = nH; arrange(); }
// 建構式。
function SampleScrollBar() { init(); createChildren(); arrange(); }
// 本文提到的init()方法
private function init():Void { __width = _width; __height = _height; _xscale = 100; _yscale = 100; mx.events.EventDispatcher.initialize(this); mcBoundingBox._visible = false; mcBoundingBox._width = 0; mcBoundingBox._height = 0; }
// createChilnden()方法設定上下捲動按鈕、scroll track和scroll thumb bar。
// 雖然你也可以在類別裡定義,但是這個例子我們在createChildren()方法中指定
// onPress()、onRelease()和onReleaseOutside()方法。
private function createChildren():Void { attachMovie("ScrollUp", "_mcScrollUp", getNextHighestDepth()); attachMovie("ScrollTrack", "_mcScrollTrack", getNextHighestDepth()); attachMovie("ScrollDown", "_mcScrollDown", getNextHighestDepth()); attachMovie("ScrollThumb", "_mcScrollThumb", getNextHighestDepth()); _mcScrollThumb.onPress = function():Void { this._parent._nOffset = this._ymouse; this._parent._nInterval = setInterval(this._parent, "scroll", 10); }; _mcScrollThumb.onRelease = function():Void { clearInterval(this._parent._nInterval); }; _mcScrollThumb.onReleaseOutside = _mcScrollThumb.onRelease; _mcScrollUp.onPress = function():Void { this._parent._nInterval = setInterval(this._parent, "nudge", 10, -1); }; _mcScrollUp.onRelease = function():Void { clearInterval(this._parent._nInterval); }; _mcScrollUp.onReleaseOutside = _mcScrollUp.onRelease; _mcScrollDown.onPress = function():Void { this._parent._nInterval = setInterval(this._parent, "nudge", 10, 1); }; _mcScrollDown.onRelease = function():Void { clearInterval(this._parent._nInterval); }; _mcScrollDown.onReleaseOutside = _mcScrollDown.onRelease; }
// 排列所有的元素。當實體建立和尺寸縮放時,這個方法會被呼叫。
private function arrange():Void {
// 設定scroll track的高度,使它的高度等於實體高度(由__height取得)
// 減去上下按鈕的高度。 _mcScrollTrack._height = __height - _mcScrollUp._height - _mcScrollDown._height;
// 把scroll track的位置調整到向上捲動的按鈕下面。 _mcScrollTrack._y = _mcScrollUp._height;
// 把向下捲動的按鈕的位置調整到scroll track之下。 _mcScrollDown._y = _mcScrollTrack._y + _mcScrollTrack._height;
// 把scroll thumb bar放在scroll track內(向又調整1pixel)。 _mcScrollThumb._x = 1;
// 以_nScrollPosition為基礎決定scroll thumb bar的垂直的位置
var nY:Number = ((_nScrollPosition - _nMin)/(_nMax - _nMin)) * (_mcScrollDown._y - _mcScrollThumb._height); if(nY > _mcScrollDown._y - _mcScrollThumb._height) { nY = _mcScrollDown._y - _mcScrollThumb._height; } else if(nY < _mcScrollTrack._y) { nY = _mcScrollTrack._y; } _mcScrollThumb._y = nY; }
// 當thumb bar被使用者拖曳時,此方法被不斷呼叫。
This method is called at an interval when the thumb bar is dragged by the user.
private function scroll():Void {
// 以_ymouse的位移決定thumb bar的垂直位置。
// 同時也計算最大和最小值的範圍。如果滑鼠的值超過了最大或最小值,就把數值鎖定,讓thumb bar不跑到scroll track之外。 var nY:Number = _ymouse - _nOffset; var nUpper:Number = _mcScrollTrack._y; var nLower:Number = _mcScrollDown._y - _mcScrollThumb._height; if(nY > nUpper && nY < nLower) { _mcScrollThumb._y = _ymouse - _nOffset; } else if(nY < nUpper) { _mcScrollThumb._y = nUpper; } else if(nY > nLower) { _mcScrollThumb._y = nLower; }
// 使用自訂的dispatchScrollEvent()派遣事件。(在後面定義。)
dispatchScrollEvent(); updateAfterEvent(); }
// 當上下按鈕被按下時,這個方法被呼叫。功能和scroll()方法很接近。
// 你可以看看scroll()方法的註解了解更細節的部份。
private function nudge(nIncrement:Number):Void { var nUpper:Number = _mcScrollTrack._y; var nLower:Number = _mcScrollDown._y - _mcScrollThumb._height; _mcScrollThumb._y += nIncrement; if(_mcScrollThumb._y < nUpper) { _mcScrollThumb._y = nUpper; } else if(_mcScrollThumb._y > nLower) { _mcScrollThumb._y = nLower; } dispatchScrollEvent(); updateAfterEvent() }
// 如果目前的值和先前不同,派遣一個scroll事件。
private function dispatchScrollEvent():Void { if(_mcScrollThumb._y != _nPrevScroll) { dispatchEvent({type: "scroll", target: this}); _nPrevScroll = _mcScrollThumb._y; } }
}10. 儲存.as檔,並回到.fla。
11. 選擇元件庫內的ScrollBar元件,然後開啟元件定義對話框。
12. 把AS 2.0類別設定為com.person13.SampleScrollBar選擇確定。
13. 選取ScrollBar元件,點選匯出SWC選項。匯出檔案到Components/UI Components目錄下。就像之前說明的那樣。
14. 開啟一個新的.fla文件。
15. 開啟組建面板,並重新載入。ScrollBar元件應該就會出現在面板中。
16. 從組件面板拖曳ScrollBar的實體到主時間軸的舞台上。把實體的名稱設定為csbScroller。
14. 開啟元件檢測器面板。你應該可以看到max、min和scrollPosition屬性。設定他們的值為200、-200和100。
15. 使用屬性檢測器把組件的實體的高度縮放到200pixel。
16. 在主時間軸增加新的圖層,增加下面的程式碼到此時間軸的keyframe裡:
代码:
var oListener:Object = new Object();
oListener.scroll = function(oEvent:Object):Void {
trace(oEvent.target.scrollPosition);
};
csbScroller.addEventListener("scroll", oListener);17. 測試影片。當你捲動捲軸時,應該可以看到scrollPosition的值顯示在輸出面板。
結論
組件是強大而又令人疑惑的議題。希望本篇文章能夠幫助你開始寫自己的組件。本文並不打算完整的討論這個議題。有任何的意見或指正,請寫信給我,謝謝您的閱讀。
回复Comments
作者:
{commentrecontent}