Hierarkisk navigation i Adobe Flash

Denne artikel giver dig en gennemgang af hierarkisk navigation. Denne type af navigation giver et overblik over alle sider på et website, hvor relevante undersider er placeret inde i hinanden. Systemet minder om den folderstruktur, du kender fra Stifindern i Windows eller Finder på Mac.

Inden du kaster dig ud i opgaven, bør du læse om hierarkisk navigation på http://wiki.hjaelpmignu.dk/index.php?title=Metoder_til_hierarkisk_navigation

Opgavefiler

Der er ingen opgavefiler til denne opgave.

Opbyg et array med siderne

Opret et nyt dokument ( ActionScript 3.0 ).
Stil dig i første frame på laget "Layer 1" og vis panelet Actions via Window>Actions F9 (Win) Option+F9 (Mac)
Skriv følgende i frame 1:

  1. var pages:Array = [];
  2. var side1_3_1:Array = ["side1_3_1", "PDF Dokumenter", "pdf_dokumenter.swf"];
  3. var side1_3_2:Array = ["side1_3_2", "Word Dokumenter", "word_dokumenter.swf"];
  4. var side1_3:Array = ["side1_3", "Dokumenter", "dokumenter.swf", [side1_3_1, side1_3_2]];
  5. var side1_2:Array = ["side1_2", "Eksterne links", "eksterne_links.swf"];
  6. var side1_1:Array = ["side1_1", "Interne links", "interne_links.swf"];
  7. var side1:Array = ["side1", "Links", "links.swf", [side1_1, side1_2, side1_3]];
  8. var side2_1:Array = ["side2_1", "Medarbejdere", "medarbejdere.swf"];
  9. var side2_2:Array = ["side2_2", "Konsulenter", "konsulenter.swf"];
  10. var side2:Array = ["side2", "Ansatte", "ansatte.swf", [side2_1, side2_2]];
  11. var side3:Array = ["side3", "Kontaktinfo", "kontaktinfo.swf"];
  12. pages.push(side1, side2, side3);

Array's til disse sider oprettes her indefra og ud, startende med side 1's tredje niveau (1.3.1 og 1.3.2). Når de er oprettet, laves det andet niveau, der skal have dem koblet på sig osv. osv. indtil alle sider i første niveau er oprettet.

Normalt består arrayet af 3 variabler, der indeholder en unik reference, en titel på siden og et filnavn. Hvis siden indeholder undersider, er det fjerde indeks et array, med en reference til alle de oprettede "under"-array's, der hører til dem.

Lidt mere forberedende arbejde

Derudover er der et par ting mere, der skal gøres klar inden menuen kan tegnes, og siderne kan vises. Skriv følgende efter den anden kode:

  1. var padding:int = 2;
  2. var offset:int = 0;
  3. var container:Sprite = new Sprite();
  4. addChild(container);
  5. var navigation:Sprite = new Sprite();
  6. navigation.x = navigation.y = 10;
  7. addChild(navigation);
  8. showTree(pages, 1);

Her sættes padding, som er mellemrummet mellem punkterne og en variabel kaldet offset, skal holde styr på, hvor mange menupunkter, der er tegnet. Derefter oprettes der to (2) containere, en til siderne, der skal hentes og én til navigationen.

Orettelse af selve menupunktet

Vi tager det lidt i omvendt rækkefølge her, for den næste funktion du skal kigge på, er den der bliver kaldt, mens array'et gennemløbes - det er den funktion, der sørger for oprettelsen af menupunkterne. Den ser således ud:

  1. function makeLink(id:Array):Sprite
  2. {
  3. var returnObj:Sprite = new Sprite();
  4. var lbl:TextField = new TextField();
  5.  
  6. lbl.autoSize = TextFieldAutoSize.LEFT;
  7. lbl.selectable = false;
  8. lbl.text = id[1];
  9.  
  10. returnObj.addEventListener(MouseEvent.CLICK, onClick);
  11. returnObj.mouseChildren = false;
  12. returnObj.buttonMode = true;
  13. returnObj.addChild(lbl);
  14. return returnObj;
  15. }

Den modtager en parameter kaldet id af typen Array. Den indeholder menupunkterne på det aktuelle niveau.

  1. var returnObj:Sprite = new Sprite();
  2. var lbl:TextField = new TextField();

Her oprettes de objekter, der skal bruges til hvert af menupunkterne, nemlig en sprite og et tekstfelt.

  1. lbl.autoSize = TextFieldAutoSize.LEFT;
  2. lbl.selectable = false;
  3. lbl.text = id[1];

Herefter arbejdes der med tekstfeltet. autoSize sørger for at tekstfeltet skalerer sig (mod højre) så ingen tekst bliver klippet. Derefter sættes selectable til false, så teksten ikke kan markeres. Endelig fyldes den med indholdet af anden variabel (2) i array'et (indeks 1).

  1. returnObj.addEventListener(MouseEvent.CLICK, onClick);
  2. returnObj.mouseChildren = false;
  3. returnObj.buttonMode = true;

Spriten, får tilknyttet en listener, der lytter efter om der klikkes på den og kalder funktionen onClick(). Derefter sættes property'en mouseChildren til false.

TIP: mouseChildren, er faktisk en vigtig kommando, når du opretter menuknapper dynamisk, da den fjerner muligheden for interaktion, med displayobjekter der er placeret inde i den. Det gør at slt, hvad du kunne finde på at dekorere din menuknap med aldrig for lov til at overtage kommandoen i event flowet, når musen klikker på knappen.

Endelig sættes buttonMode til true, så musen ændrer sig til en hånd når spriten aktiveres.

  1. returnObj.addChild(lbl);
  2. return returnObj;

Endelig placeres tekstfeltet i spritens display list og sprite objektet returneres til det sted, funktionen blev kaldt fra.

Så skal hierarkiet gennemløbes

Til sidst (næsten) kommer selve gennemløbet af hele arrayet. Her skal der bruges en teknik, der kaldes rekursiv funktion (recursive function). Princippet bag teknikken er, at funktionen gennemløber sig selv, indtil en betingelse for at bryde ud af løkken er opfyldt.

I vores eksempel, modtager funktionen et array. Den arbejder med alle elementer i dette array, et ad gangen. Støder funktionen på et array, mens den løber elementerne igennem, kalder den sig selv, med dette array som parameter. Dette kald, vil oprette en ny funktions-løkke og fortsætte sit arbejde, indtil der ikke findes flere array.

Funktionerne skal jo lukkes, inden den funktion, der kalder dem, kan fortsætte. Derfor vil gennemløbet i en rekursiv funktion vise sig som en systematisk gennemgang af et hireakiet ... perfekt til vores formål. Sådan her ser koden ud:

  1. function showTree(tree:Array, indent:int):void
  2. {
  3. for (var i:int=0; i< tree.length; i++)
  4. {
  5. var link:Sprite = makeLink(tree[i]);
  6. link.y = 0+(link.height*offset)+(padding*offset);
  7. link.x = 0+(indent*10);
  8. navigation.addChild(link);
  9. offset++;
  10. trace("indent "+indent);
  11. // Check om niveauet har en underside.
  12. if (tree[i][3])
  13. {
  14. showTree(tree[i][3], indent + 1);
  15. }
  16. }
  17. }

Den tager vi også i mindre bidder.

function showTree(tree:Array, indent:int):void

Selve funktionen modtager 2 parametre: tree af typen Array, og indent at typen heltal (integer). Den første er en reference til arrayet med alle siderne, og det andet skal bruges til at rykke underpunkter lidt ind i forhold til deres overliggende punkt.

var link:Sprite = makeLink(tree[i]);

Derefter oprettes et objekt kaldet link. Det er resultatet af hjælpefunktionen makeLink() og sender indekset på det aktuelle menupunkt med.

  1. link.y = 0+(link.height*offset)+(padding*offset);
  2. link.x = 0+(indent*10);

Her placeres menupunktet ud af x- og y-aksen. For en dybere gennemgang af denne beregning, kan du se artiklen om forgrenet navigation. Her er dog én vigtig detalje. Variablen offset, er med i beregningen af y-positionen. Det er fordi du har tænkt dig at bruge teknikken rekursiv funktion. For at placere dem skal padding variablen have en "uvildig" og global tæller, der kan arbejde uden for funktionens gennemløb. Dermed ment: Hvis ét funktinsgennemløb sluttede ved offset 5, skal den næste gerne fortsætte med offset 6 ... variabler oprettet inde i funktioner, dør sammen med funktionen.

  1. navigation.addChild(link);
  2. offset++;

Så tilføjes linket til objektet og offset forøges med én (1). Til sidst kommer selve nerven i den rekursive funktion.

  1. if (tree[i][2])
  2. {
  3. showTree(tree[i][2], indent + 1);
  4. }

i if()-løkken tjekkes der for om der findes et indeks 2. Hvis der gør det, er det fordi der er et array med underpunkter. Når denne betingelse bliver opfyldt, bliver dette array sendt afsted som parameter i et funktionskald til showTree() - det betyder altså, at du kalder en udgave af den funktion du pt. er midt i. Den anden parameter der sendes af sted er værdien af indent + 1. Det er den samme værdi som ryger ind som en parameter i funktionen, så den bliver sendt videre, forhøjet en enkelt.

Den sidste stump kode

Den sidste del, jeg har tænkt mig at gennemgå her i artiklen, er sådan set bare, at fange noget, fra det menupunkt, der klikkes på. Koden ser således ud.

  1. function onClick(e:MouseEvent):void
  2. {
  3. trace("Klikker på " + e.target.getChildAt(getChildByName("lbl")).text);
  4. }

Denne funktion, onClick() er den der kaldes når der klikkes på et punkt. Den kalder en trace() kommando. For at navigere ned igennem den lidt ad gangen fanger e.target selve knappen. getChildAt() fanger et displayobjekt på et bestemt indeks. For at finde indekset, er du nød til at bruge getChldByName() for at få at vide, hvilket indeks objektet lbl befinder sig på ("lbl" var navet på tekstfeltet. Når den er peget ud, fanges dens text property.

Jamen, vi er jo ikke færdig

Nej, men der er grænser for, hvor meget der kan behandles i én og samme artikel. Det er meningen du selv skal arbejde videre herfra. Har du gennemgået artiklerne om lineær navigation og forgrenet navigation, har du egentlig alle værktøjerne til, at få vist alle siderne. Her er et par punkter du kan tage fat på:

Du har en sprite til hver punkt, der kan dekoreres videre på. Du kan instantiere grafik, du har liggende i biblioteket, eller du kan bruge graphics klassen, som de fleste display objekter har adgang til.
Du kan bruge name-property'en fra sprite objketet til at opbevare informationer om filnavnet på den side, der skal hentes.
Du kan bruge MouseEvent.MOUSE_OVER og MouseEvent.MOUSE_OUT til at ændre farve på teksten, når den aktiveres af musen.

God fornøjelse, og husk. Det sjoveste er at eksperimentere videre på egen hånd. Tilsidst får du lige koden i sin helhed:

  1. var pages:Array = [];
  2. var side1_3_1:Array = ["side1_3_1", "PDF Dokumenter", "pdf_dokumenter.swf"];
  3. var side1_3_2:Array = ["side1_3_2", "Word Dokumenter", "word_dokumenter.swf"];
  4. var side1_3:Array = ["side1_3", "Dokumenter", "dokumenter.swf", [side1_3_1, side1_3_2]];
  5. var side1_2:Array = ["side1_2", "Eksterne links", "eksterne_links.swf"];
  6. var side1_1:Array = ["side1_1", "Interne links", "interne_links.swf"];
  7. var side1:Array = ["side1", "Links", "links.swf", [side1_1, side1_2, side1_3]];
  8. var side2_1:Array = ["side2_1", "Medarbejdere", "medarbejdere.swf"];
  9. var side2_2:Array = ["side2_2", "Konsulenter", "konsulenter.swf"];
  10. var side2:Array = ["side2", "Ansatte", "ansatte.swf", [side2_1, side2_2]];
  11. var side3:Array = ["side3", "Kontaktinfo", "kontaktinfo.swf"];
  12. pages.push(side1, side2, side3);
  13.  
  14. var padding:int = 2;
  15. var offset:int = 0;
  16. var container:Sprite = new Sprite();
  17. addChild(container);
  18. var navigation:Sprite = new Sprite();
  19. navigation.x = navigation.y = 10;
  20. addChild(navigation);
  21. showTree(pages, 1);
  22.  
  23. function showTree(tree:Array, indent:int):void
  24. {
  25. for (var i:int=0; i< tree.length; i++)
  26. {
  27. var link:Sprite = makeLink(tree[i]);
  28. link.y = 0+(link.height*offset)+(padding*offset);
  29. link.x = 0+(indent*10);
  30. navigation.addChild(link);
  31. offset++;
  32. trace("indent "+indent);
  33. // Check om niveauet har en underside.
  34. if (tree[i][3])
  35. {
  36. showTree(tree[i][3], indent + 1);
  37. }
  38. }
  39. }
  40.  
  41. function makeLink(id:Array):Sprite
  42. {
  43. var returnObj:Sprite = new Sprite();
  44. var lbl:TextField = new TextField();
  45.  
  46. lbl.autoSize = TextFieldAutoSize.LEFT;
  47. lbl.selectable = false;
  48. lbl.text = id[1];
  49.  
  50. returnObj.addEventListener(MouseEvent.CLICK, onClick);
  51. returnObj.mouseChildren = false;
  52. returnObj.buttonMode = true;
  53. returnObj.addChild(lbl);
  54. return returnObj;
  55. }
  56.  
  57. function onClick(e:MouseEvent):void
  58. {
  59. trace("Klikker på " + e.target.getChildAt(getChildByName("lbl")).text);
  60. }

Comments

Post new comment

  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <as3>, <javascript>, <php>. The supported tag styles are: <foo>, [foo].
  • You may link to webpages through the weblinks registry
  • You may quote other posts using [quote] tags.
  • Textual smileys will be replaced with graphical ones.

More information about formatting options

CAPTCHA
Denne test er for at sikre at du er en reel bruger i stedet for en automatisk forespørgsel på en side. Spørgsmålet er for at undgå spam af sitet - tak for din forståelse
Image CAPTCHA
Enter the characters shown in the image.