Creating New Components in Flex 3 and Beyond @ MAX 2008
Speakers: Matt Chotin
Túto prednášku som síce nemal v pláne, ale keďže prednáška “Optimizing Adobe AIR for Code Execution, Memory, and Rendering” bola zrušená, táto padla vhod. Prednáška sa z dvoch tretín venovala Flex 3 komponentom a zvyšná tretina Gumbo komponentom.
Slovník
Životný cyklus Flex komponentu
Životný cyklus Flex komponentu je mechanizmus, ktorý Flex framework využíva na vytvorenie, správu a zánik komponentov a je navrhnutý tak aby z Flash Player-a vyťažil čo najviac.
Halo
Halo je komponentová architektúra použitá pre Flex 3 (framework) a skoršie verzie.
Gumbo/Spark
Gumbo je pracovné označenie novej verzie Flex (framework) a Flex Builder-a. Spark je označenie pre komponentovú a skinning architektúru použitú v Gumbo.
Spark je rozšírením Halo architektúry.
Parts/Časti
Väčšina komponentov sa skladá z menších prvkov, ktoré nazývame Parts/časti. Ak si predstavíme napríklad Scrollbar, tak jeho časťami v tom najjednoduchšom prípade sú thumb a track (posuvník a plocha pod ním). Tieto časti tvoria deti komponentu. Teda nielen kontajnery ako ich poznáme z Flexu ale aj komponenty môžu mať deti.
Vzory Halo architektúry
Koncepty použité v Halo architektúre, sú dôležité pre porozumenie benefitov, ktoré ponúka Spark.
Halo architektúra využíva Invalidation/Validation model. Je to model, ktorý zabezpečuje agregáciu zmien a oddialenie práce do optimálneho času. Znamená to asi toľko, že ak nastavím nejaký parameter komponentu, napr. pozícia tlačidiel video prehrávača, tak zmeny sa neudejú okamžite, ale sú odložené dovtedy, kým nenastane vhodný čas. To ktorý čas to je a kedy nastane (Validation) sa dočítame neskôr v tomto článku.
Ďalším vzorom je Event Interaction Model. Vo Flex-e je všetko o eventoch (udalostiach), čokoľvek čo robíte je riadené udalosťami. Či je to už enterFrame udalosť prichádzajúca s posuvom hlavy prehrávača na každú jednu snímku, sieťová udalosť prichádzajúca s dátami zo servera alebo ako odozva interakcie užívateľa. Udalosť je informáciou, že sa v komponente niečo má stať alebo sa už stalo.
Komponent sa skladá z častí. Tieto časti majú byť konfigurovateľné a parametrizovateľné, ako napr. štýl komponentu, pozícia ovládacích prvkov atď. Dobrým príkladom je aj prispôsobenie zoznamov (List). Bola by teda škoda ak by programátor bol nútený pre prispôsobenie bunky zoznamu dediť triedu komponentu a prepisovať jej metódy. Preto by mali komponenty ponúkať parametre ako itemRenderers a factories a umožniť tak vložiť svoj vlastný look-and-feel bunky listu. Takýto model nazývame kompozícia — umožní vyskladať a prispôsobiť si komponent na svoj vlastný obraz.
Životný cyklus komponentu je rozdelený do troch častí.
- Inicializácia (Initialization)
- Konštrukcia (Construction)
- Konfigurácia, (Configuration)
- Pripojenie, (Attachment)
- Inicializácia, (Initialization)
- Aktualizácia (Updating)
- Komponent odpovedá na zmeny pomocou Invalidation/Validation modelu
- Zánik (Destruction)
- Zíde z očí, zíde z mysle
- Odpojenie, Detachment
- Garbage collection
1.1 Konštrukcia/Construction
Je to čas, kedy sa rozhodnete, že váš komponent potrebuje existovať. Prvé dôležité rozhodnutie bude, z čoho bude váš komponent odvodený, z ktorej triedy bude dediť. Najnižšia trieda v hierarchii, z ktorej možno vo Flexe dediť komponenty je trieda UIComponent. Obsahuje tie najzákladnejšie vlastnosti a metódy pre Flex komponenty.
V ďalšom na čo by ste mali myslieť je, čo sa stane keď sa komponent inicializuje (instanciuje). Bude vytvorený cez ActionScript pomocou new operátora, alebo bude vytvorený cez MXML? Ak má byť požiadavka aby bol komponent vytváraný cez MXML, nemal by konštruktor obsahovať žiadne povinné atribúty. Je možné použiť voliteľné argumenty ale ako Matt spomenul best practice Flex SDK komponentov je čo najväčší možný počet bez-argumentových konštruktorov.
V konštruktore by sa malo odohrávať čo najmenej práce. Je možné pridávať napríklad event listenery (na vlastný komponent) ako FlexEvent.CREATION_COMPLETE, MouseEvent-y, ktoré bude komponent handlovať, inicializovať konštanty a podobne.
1.2 Konfigurácia/Configuration
Vlastnosti komponentov sú v tejto fáze nastavené interne a čakajú na neskoršie spracovanie, tzn. že hodnoty vlastností sú nastavené ešte predtým než sú do komponentu pridané akékoľvek časti (deti). Vlastnosti teda musia predpokladať, že časti komponentov ešte nemusia existovať. Prakticky sa hodnoty vlastností len uložia (do storage premenných) a spracujú sa neskôr, akonáhle budú deti komponentu existovať. Príkladom takejto konfigurácie môže byť vlastnosť source video prehrávača. Setter pre source uloží hodnoty do premenných a oddiali ďalšiu prácu na vhodný čas. Časť video prehrávača, ktorá zobrazuje video, nemusi v čase, keď setter ukladá hodnoty existovať.
1.3 Pripojenie/Attachment
Je to fáza, kedy je komponent pridaný do display listu. Každý vizuálny objekt, ktorý má byť zobrazený sa stáva dieťaťom display listu niekde v jeho stromovej štruktúre. Komponent je do tejto hierarchie pridaný cez addChild() metódu jeho rodiča. Bez pripojenia do display listu sa životný cyklus komponentu zastaví.
1.4 Inicializácia/Initialization
Poslednou fázou prvej časti životného cyklu komponentu je inicializácia. V tejto fáze sa začína prvý Invalidation/Validation cyklus.
Počas inicializácie prebehne 5 akcií: 1. vyšle sa preinitialize udalosť - hovorí o tom, že komponent bol vytvorený (alias konštruktora ak používate markup), vlastnosti boli nastavené a komponent bol pridaný do display listu (má nastavenú parent vlastnosť resp. má rodiča) 1. zavolá sa createChildren() metóda - je to metóda, v ktorej sa fyzicky vytvárajú časti komponentu 1. vyšle sa initialize udalosť - akonáhle boli vytvorené časti komponentu, vyšle sa initialize event 1. nastane prvý kompletný Invalidation/Validation cyklus 1. vyšle sa creationComplete udalosť
Celá logika komponentu by mala začať fungovať až na FlexEvent.CREATION_COMPLETE event. Preinitialize a initialize udalosti by mali byť určené na spúšťanie základných konfiguračných a špecifických inicializačných procesov vo vašom komponente.
Metóda createChildren()
Metóda, kde komponent vytvára svoje časti, ktoré sú vyžadované počas celého životného cyklu komponentu. Príkladom môže byť display video prehrávača. Display by mal byť viditeľný vždy, na rozdiel napríklad od ovládacích prvkov video prehrávača, ktoré môžu byť voliteľné.
Ak komponent obsahuje dynamicky vytvárané časti, ktoré sa majú zobrazovať napríklad na základe nejakej udalosti alebo vlastnosti, tieto časti sa v createChildren() metóde nevytvárajú a namiesto toho sa použije napríklad commitProperties() metóda. Vytváranie dynamických častí komponentu neskôr odľahčuje túto metódu.
Niektoré pravidlá Halo architektúry:
- UIComponent môže obsahovať čokoľvek (Sprites, Shapes, MovieClips, Video …)
- UIComponent musí mať rodiča UIComponent
- Container môže obsahovať iba UIComponent-y (pridanie napr. Sprite vyhodí runtime exception)
Po createChildren() nasleduje initialize udalosť a prvý a plný Invalidation/Validation cyklus.
Invalidation je fáza, ktorá je popísaná troma metódami:
- invalidateProperties()
- invalidateSize()
- invalidateDisplayList()
Validation je fáza, ktorá je popísaná nasledujúcimi metódami:
- commitProperties()
- measure()
- updateDisplayList()
Volanie invalidačných metóda zabezpečí vývojár a volanie validačných metód zabezpečuje framework, v žiadnom prípade vývojár. Volanie invalidateProperties() volá commitProperties(), volanie invalidateSize() volá measure() a volanie invalidateDisplayList() zabezpečí volanie updateDisplayList() v správny čas. Poradie volania validačných metód zodpovedá poradiu v zozname vyššie.
Po tomto cykle je odoslaná creationComplete udalosť a prvá fáza životného cyklu komponentu (Inicializácia) je ukončená.
2.1 Aktualizácia/Updating
Komponent bol vytvorený, žije svoj príbeh a potrebuje vedieť ako sa aktualizovať. To pre neho zabezpečuje fáza 2.
Aktualizácie nastávajú vtedy ak užívateľ pracuje s komponentom alebo ak iné časti kódu volajú/nastavujú metódy/vlastnosti komponentu. Pre odozvu na zmeny by mal komponent využívať Invalidation/Validation model. Dôvodov je viac.
Jeden z najzásadnejších, si vyžaduje minimálne znalosti fungovania Flash Player-a. Flash ako taký pracuje so snímkami/frames. Flash aplikácie môžu pracovať na 12 snímkov za sekundu, animácie 24-25 snímkov za sekundu atď (extrémne nízky alebo vysoký frame rate je už iná debata). Horná hranica snímkov za sekundu sa dá vo Flash Player-i jednoducho nastaviť a väčšinou je vždy rešpektovaná, avšak určite nie je rešpektovaná ako spodná hranica, a to z dôvodu ako funguje Flash Player elastic racetrack - dráha ktorú prejde Flash Player pri jednom snímku.
(autor: Sean Christmann)
Predstavme si, že sa po dráhe pohybujeme v smere hodinových ručičiek a začiatok dráhy je naspodu. Flash Player je od prírody jedno vláknový (single thread) a všetko čo vie robiť je spúšťať kód alebo renderovať, čiže delí svoj čas na dve časti. V prvej polovici spúšťa kopec kódu, dokončí spúšťanie a v druhej polovici dráhy začne renderovať. Renderovanie nemáme pod kontrolou, riadi ho Flash Player. Rendering je odpoveďou na to, čo sme spravili v našom kóde v predošlej polovici dráhy.
Heavy code execution
Čo sa však stane ak spúšťanie nášho kódu zaberie dlhý čas? Keďže Flash Player je single thread, nepovie počkaj-počkaj, musím renderovať, ale nechá nás dokončiť všetok kód. Ak modrá časť dráhy je príliš veľká, nastane moment výnimky na Script Limit a Flash Player vyhlási, že spúšťanie kódu trvalo príliš dlho. To je signálom, že robíme niečo zle a musíme časť spúšťaného kódu odložiť na neskôr.
Heavy rendering
Ak máme v display liste veľké množstvo display objektov, dráha sa predlžuje v rendering časti. To môžeme jedine ovplyvniť tým, že sa zamyslíme nad tým, prečo máme toľko vecí v display liste a snažíme sa ich zredukovať :)
Životný cyklus Flex komponentu je postavený na základoch tohto frame modelu. Invalidation/validation proces profituje z elastic racetrack modelu a snaží sa spraviť si svoju prácu čo najefektívnejším spôsobom.

Opäť začíname na dráhe od spodu a v smere hodinových ručičiek. Kód je spustený až sa dostane cez celú modrú čiaru až na koniec. Počas tohto času (Invalidation) možeme v komponente zmeniť ľubovoľne veľa vlastností, zavolať ľubovoľne veľa metód, ale snažíme sa oddialiť prácu súvisiacu s renderovaním až na úplný koniec (Validation). Je to z toho dôvodu, že render prebehne len raz - Flash Player sa nedá prinútiť aby renderoval viac krát za snímku alebo skôr.
Toto je základný Invalidation/Validation model. Komponenty sedia v aplikácii, sú šťastné, čakajú na aktualizáciu. Niečo sa stane, prebehne aktualizácia. Počas aktualizačného procesu voláme invalidačné invalidateNiečo() metódy a na konci cyklu prebehne validácia. Po nej začne Flash Player renderovať. Invalidation/Validation model je rozdelený do troch fáz:
- Aktualizácia vlastností komponentu:
invalidateProperties()->commitProperties() - Aktualizácia veľkosti and rozmerov:
invalidateSize()->measure() - Aktualizácia pozície a kreslených objektov:
invalidateDisplayList()->updateDisplayList()
1. commitProperties()
Metóda zabezpečuje manažment vlastností (properties) komponentu. Ak sa zmení v komponente čokoľvek čo ovplyvní vlastnosti komponentu, zavoláme invalidateProperties() aby sme komponent označili ako zmenený (dirty) a následne vo Validation fáze sa zavolá commitProperties(). Táto metóda je volaná pred measure() a updateDisplayList() metódami.
Flex Framework využíva na handlovanie vlasností vzor, ktorý nastavuje “dirty” príznaky a storage premenné. Modrú časť elastic racetrack sa snažíme udržať tenkú a rýchlu, ako je to len možné. “Dirty” príznaky nám umožnia filtrovať prácu v komponente na takú, ktorá skutočne musí byť vykonaná, čiže sa odstráni opakovanie spúšťania kódu.
Metoda commitProperties() poskytuje je skvelý čas na add/remove detí, ktoré NIE sú vyžadované počas celého životného cyklu komponentu. Všetky dynamické časti, ktoré sa majú pridať alebo ubrať na základe zmeny vlastností sa pridávajú a uberajú práve v commitProperties() na rozdiel od statických častí, ktoré sú vytvárané v createChildren().
// ...
// default hodnota
private var _volume : Number = 4;
// dirty flag
private var volumenChanged : Boolean;
[Bindable("volumeChanged")]
public function get volume() : Number
{
return _volume;
}
public function set volume(value : Number) : void
{
// iba v pripade ak sa hodnota lisi od uz nastavenej
if(_volume != value)
{
// nastav
_volume = value;
// oznac ako dirty
volumeChanged = true;
// invaliduj
invalidateProperties();
// dispatch bindable event
dispatchEvent(new Event("volumeChanged"));
}
}
// invalidateProperties zavola ...
override protected function commitProperties() : void
{
// vzdy volame super, aby sa aj nas rodic dozvedel o validacii
super.commitProperties();
// ak je premenna dirty
if(volumeChanged)
{
// validuj
_soundTransform.volume = _volume/10;
netStream.soundTransform = _soundTransform;
volumeTrack.value = _volume;
// nezabudni vycistit dirty priznak!!!
volumeChanged = false;
}
// ...
}
2. measure()
Metóda measure() je volaná vo fáze validácie a je určená zmene veľkosti komponentu, resp. jej prepočítaniu. Je to čas, kedy komponent vypočíta svoju prirodzenú veľkosť, založenú na obsahu a layout pravidlách. Je to veľkosť, ktorú komponent preferuje mať. Využíva informácie o veľkosti svojich detí, layout pravidlá, layout contstrains atď. nato aby zistil svoju požadovanú veľkosť.
Meranie veľkosti prebieha zospodu nahor.
<mx:Application>
<mx:HBox>
<mx:Button/>
</mx:HBox>
</mx:Application>
Button povie svojmu rodičovi (HBox) aký veľký chce byť. V ďalšom povie HBox svojmu rodičovi (Application) aký veľký chce byť. Keďže measure() prebieha odspodu navrch, nie je nutné volať measure() na každom dieťati zvlášť, pretože v čase ako sa volá measure() na komponente, measure() dieťaťa bola už dávno zavolaná.
“Measure is kind of curious piece.”
Framework optimalizuje volania measure() na tie najnutnejšie. Povedzme, že máme nastavenú explicitnú veľkosť komponentu - measure() sa nikdy nezavolá, pretože frameworku postačuje explicitné nastavenie veľkosti nato aby určil aký veľký komponent má byť. measure() sa tiež nemusí zavolať ak sa použivajú iné layout pravidlá, layout constrains a podobne.
Pre nás ako tvorcov komponentov to znamená - nikdy nedávať závislý kód do measure() metódy, pretože sa môže ľahko stať, že sa metóda nikdy nezavolá.
measure() metóda nastavuje štyri vlastnosti:
measureWidth,measureHeightmeasureMinWidth,measureMinHeightoverride protected function measure() : void { // nezabudnime volat super() super.measure();
var placement : String = getStyle('controlBarPlacement'); if(!placement) { placement = "bottom"; } var bm : EdgeMetrics = borderMetrics; if(placement == "bottom" || placement == "top") { measuredWidth = Math.max(video.width, controlBar.getExplicitOrMeasuredWidth()) + bm.left; measuredHeight = bm.top + video.height + controlBar.getExplicitOrMeasuredHeight(); } else if(placement == "left" || placement == "right") { measuredWidth = controlBar.getExplicitOrMeasuredWidth() + video.width; measuredHeight = Math.max(controlBar.getExplicitOrMeasuredHeight(), video.height) + bm.top; } // bezne je nastavit minima na zmerane hodnoty measuredMinWidth = measuredWidth; measuredMinHeight = measuredHeight;}
getExplicitOrMeasuredWidth/Height() sa volá na UIComponente pre zistenie jeho veľkosti, pretože môže byť nastavená explicitne alebo ju bude treba predtým než sa vráti zmerať.
3. updateDisplayList()
Ak skončila validačná measure() metóda, prechádzame na ďalšiu validačnú metódu updateDisplayList(). Účelom tejto metódy, je rozloženie obsahu komponentu a dodatočné kreslenie, inými slovami - ideme ukladať a dokreslovať deti.
Rozloženie a nastavenie pozície častí komponentu prebieha naopak ako ich meranie - Zhora nadol.
<mx:Application>
<mx:HBox>
<mx:Button />
</mx:HBox>
</mx:Application>
Funguje to asi tak, že Application umiestni svoje deti (HBox) a HBox umiestni svoje deti (Button). V metóde updateDisplayList() je treba umiestniť a veľkostne prispôsobiť každú jednu časť komponentu.
Platia tu isté pravidlá:
- ak dieťa, ktoré idem zväčšiť/zmenšiť a/alebo umiestniť je UIComponent, použijem
setActualSize()pre zmenu veľkosti amove()pre zmenu pozície. Je to z toho dôvodu, že keď nastavujeme width, height, x a y na UIComponent-e, tak sa dispatčujú move a resize eventy, ktoré sú postupne zachytené a vykonané za sebou. Namiesto toho sa používajú tieto dve metódy, ktoré agregujú move a/alebo resize eventy a vysielajú ich naraz. - ak dieťa nie je UIComponent, nastavujeme
width,height,xaypriamo cez vlastnosti.
“updateDisplayList() je ideálne miesto pre použitie Flash Player Drawing API.”
Style support
Podpora štýlov je pripravená priamo v UIComponent-e. Našou požiadavkou je, aby sme užívateľovi nášho komponentu umožnili inline zmenu štýlov a vlastností súvisiacich so štýlmi. Na to aby sme mohli nastaviť štýl inline v MXML ako atribút, je nutné zadefinovať metadáta pre komponent, ktoré dekorujú triedu a dajú kompileru a IDE informácie o tomto štýle:
[Style(name="textSelectedColor", type="uint", format="Color", inherit="yes")]
Default hodnotu stýlu nastavíme priamo v komponente alebo v default.css súbore. Štýly sa môžu meniť run-time. Ak chceme komponent začleniť do run-time styling mechanizmu, musíme prepisať styleChanged() metódu a zadefinovať, ako má komponent reagovať na zmenu štýlu. Táto metóda skontroluje, ktorý štýl sa zmenil a nastaví správnu invalidáciu.
override public function styleChanged(styleProp : String) : void
{
super.styleChanged(styleProp);
if(styleProp == "controlBarPlacement")
{
invalidateSize();
invalidateDisplayList();
}
}
Hint: Aké vlastnosti komponentu naprogramovať ako štýl?:
- ak daná zamýšlaná vlastnosť má viac dočinenia s prezentáciou, mal by to byť štýl,
- ak máme konštantu, ktorá má dočinenia s prezentáciou, mal by to byť štýl.
Udalosti vo Flex-e
Každý komponent by mal byť schopný počúvať na a vysielať udalosti. Ak potrebujeme mať udalosť nastaviteľnú a dostupnú inline z MXML, musíme opäť použiť metadáta pre event:
[Event(name="ready", type="mx.events.VideoEvent")]
Metadáta hovoria o tom, ako sa udalosť, ktorá je vysielaná volá a taktiež aký ma typ. Výhodou je používať vlastné triedy udalostí rozšírené napríklad od mx.events.Event. V takejto triede možeme ďalej definovať statické premenné ako názvy udalostí a tým dosiahnúť compile-time kontrolu na typy eventov. Pomocou rozšírených event tried vieme definovať ďalšie dodatočné informácie/vlastnosti vhodné pre event handlery.
Hint: používajte desktriptívne názvy udalostí.
3. Destroying the component!
Príde čas kedy aj váš komponent bude zapísaný do čiernej kroniky. Prvá vec, ktorá sa vykoná je detachment, alebo odparentovanie :) Komponent sa odstráni z display listu cez removeChild() volanie. To spôsobí, že komponent nie je validovaný alebo prekreslovaný resp. Invalidation/Validation a draw metódy nefungujú!
removeChild() vracia referenciu na odstránený dokument, ktorú môžeme uschovať pre jeho reinkarnáciu (komponent nebude odstránený z pamäti cez garbage collector) ako napr. adopcia iným rodičom alebo niečo ako znovu-vytvorenie. Takýto spôsob znovu-využívania komponentov je oveľa lacnejší ako vytvorenie kompletne nového komponentu. Flex framework je plný takýchto príkladov (viď Datagrid).
O kompletné odstránenie komponentu z pamäti sa stará Garbage Collector (gc). Gc zoberie spolu so sebou do večných lovíšť celý komponent len v prípade, že sa na komponent neviažu žiadne referencie. Takýmito referenciami sa myslia napríklad event listenery, dictionaries (slovniky) alebo Timers.
Hint:
- používajte parameter
useWeakReferencess hodnotou “true” preaddEventListenermetódu, potom ak jediná referencia na objekt je event listener samotný, tak bude objekt bude vymazaný z pamäte.
this.addEventListener(FlexEvent.CREATION_COMPLETE, creationComplete_Handler, false, 0, true);
- takisto pre Dictionary plati, že slovníky môžu byť vytvorené s parametrom
useWeakReferences, potom ak jediná referencia na objekt je kľúč slovnika tak bude vymazaný z pamäte.
dict = new Dictionary(true);
Touto vetou končí aj popis životného cyklu komponentu vytvoreného na Halo architektúre.
Z Halo do Spark
Ako sme povedali na začiatku, komponentová architektúra Halo používa nasledovné vzory:
- Invalidation/Validation Model
- Event Driven Interaction Model
- Composition
Tieto vzory stále existujú v komponentovej architektúre Spark. Spark však pridáva svoje vlastné vzory. Jeden z nich je “separácia komponentovej logiky od jej vizuálu”.
Komponenty majú vlastnú “triedu komponentu”, v ktorej je zadefinovaná logika a funkcionalita celého komponentu, ktorá nemá nič spoločné s vizuálom komponentu. V tejto triede neexistuje žiadna logika, ktorá diktuje vizuál a look-and-feel komponentu. Namiesto toho má komponent pridelenú “skin triedu”, ktorá obsahuje všetky informácie pre layout a look-and-feel komponentu - čokoľvek vizuálne sa nachádza v tejto “skin triede”. Tieto dve triedy navzájom komunikujú, ale sú od seba galvanicky oddelené. Trieda komponentu je napisaná v čistom ActionScript-e, a skin trieda je napisané v MXML.
Ďalšou vlastnosťou okrem toho, že logika je od prezentácie úplne separovaná je kompozícia funkcionality. V Halo ak mal napríklad List komponent List single selection, mal aj multiple selection. Keď sme multiple selection nepotrebovali, nemali sme možnosť ju odstrániť z komponentu, iba vypnúť (resp. nezapnúť). Spark to vnima celkom ináč. List komponent má single seleciton vloženú “by default” a ak by sme chceli použiť multiple selection, tak by sme si ju museli osobitne pridať do komponentu. To umožňuje postaviť komponent na mieru, tak aby bol dostatočne malý a rýchly.
Vzor, ktorý je vraj pravdepodobne najdôležitejším vzorom v Spark je “dizajnér-developer” kontrakt udržiavaný cez dáta, časti a stavy (data, parts, states) komponentu. Dáta, časti a stavy sú nám už viac menej jasné, jedine dodať, že stavy ako boli definované v Halo sa používajú rovnako aj teraz avšak všade tam, kde to je možné. Predstavme si napríklad tlačidlo, ktoré môže mať up-state, down-state a over-state. To všetko sa deje v triede komponentu (component class) a táto trieda je zodpovedná za to, že nastaví skin triedu (skin class) do požadovaného stavu, takže je jednoduché editovať vizuál komponentu v jeho jednotlivych stavoch. Komponent sa nestará o to ako sám vyzerá, pretože za všetko je zodpovedná skin trieda a takisto skin trieda sa zase nemusí odvolávať na žiadny kód v komponente aby zmenila svoj vizuál a layout.
Switchujeme na Gumbo
- Posaďte sa a popremýšlajte - pre mňa vždy najdôležitejšia časť kódovania. Zalejem si kávu, vyhodím zvyšky slaniny z klávesnice a premyslím si čo je základnou funkcionalitou môjho komponentu, čo je dôvodom jeho života - to bude to, čo vložíme do našej komponentovej triedy. Ostatné vlastnosti, možnosti a funkcionality budú nabaľované na triedu neskôr. Napríklad pre video prehrávač platí, že jeho základnou funkcionalitou je prehrávanie videa, resp. video display. Ak niekto bude chcieť play button, bude mať play button ako dodatočnú funkcionalitu.
- Spíšte časti (deti) skinu - treba identifikovať všetky časti skinu, tak aby sa dali v ďalej upravovať. Rozdelíme skin na dve časti:
- prvá čast obsahuje skutočne potrebné časti, ktoré budu existovať po celý život komponentu (napr. video display)
- druhá čast obsahuje voliteľné časti ako napríklad play button, pause buton, volume slider a ostatné ovládacie prvky, ktoré sú dynamické a môžu existovať len určitú dobu
- Pridajte Spark-špecifický kód - ako prvé si zvolím správnu základnú triedu od ktorej budem dediť. Gumbo obsahuje množstvo nových tried, ktoré majú zapúzdrené nové funkcionality. Implementujte
partAdded()apartRemoved()metódy, ktoré sú kľúčové metódy životného cyklu komponentu. Tieto metódy sú volané práve vtedy, keď sú časti komponentu pridávané alebo uberané. Tieto metódy handlujú vytváranie častí, pridávanie a odoberanie event listenerov a pod. V ďalšom je nutné dohodnúť sa na správnych stavoch. Ak viem, že môj komponent bude obsahovať viac stavov ako tie čo zdelil od rodičovskej triedy, identifikujem ich a dopíšem. Následne vytvoríme skins, to je kreatívna časť, kedy deklaratívne píšeme naše skin triedy, v hojnej miere aplikujeme markup a nové MXML graphics tagy. MXML graphics je množina tagov uvedená v Gumbo, ktoré obalujú renderovacie možnosti Flash Player-a. Sú to Graphics tags a Graphics primitives ako <Rect>, <Fills>, <Stroke>, Blend módy a všetky tie nádherné veci, ktoré Player dokáže. Takže máme komponent triedu, máme skin triedu, ako ich galvanicky previažem? - jednoducho, cez css. - Ak ste si mysleli, že už nič zaújimavšie vás nečaká, tak v tento krok je prekvapenie - vyhodíme kopec kódu :) V Gumbo svete, nepotrebujem viac
createChildren(), pretože metódypartAdded()apartRemoved()handlujú tvorbu a zrušenie častí komponentu.measure()aupdateDisplayList()sú nám na dve veci, pretože od teraz všetko handluje skin. Skin meria ako veľký chce byť, skin umiestňuje svoje časti.
Zhrnutie
Od prednášky som očakával veľa, a veľa som aj dostal. Autorka prezentácie, dala k dispozícii zdrojové kódy z prednášky a taktiež je k dispozícii aj záznam prednášky.
Flash Player Elastic Track - Learn it, love it, live it - dôležitý koncept, s ktorým je nutné sa skamarátiť. Snažíme sa udržať dráhu čo najokrúhlejšiu a čo najkratšiu. Ako to dosiahneme? Využijeme Invalidation/Validation model (all the cool kids doing it). Komponent dokáže byť s týmto modelom rýchlejší a chytrejší. Najlepšiu referenciu kódu životného cyklu komponentov máte priamo pred sebou - kód Flex framework-u.
Zdroje: http://iamdeepa.com/blog/?p=39 http://tv.adobe.com/#vi+f15384v1002 http://opensource.adobe.com/wiki/display/flexsdk/Gumbo http://opensource.adobe.com/wiki/display/flexsdk/Gumbo+Component+Architecture
Blog comments powered by Disqus