Lag en Super Modern Elastisk Meny i AS3

Create en Super Modern Elastisk Meny i AS3
Del
Del
Del
Del
Dette Cyber ​​Monday Envato Tuts + kurs vil bli redusert til bare $ 3. Ikke gå glipp av.

Noen ganger du bare ønsker å være svært moderne om ditt nettsted. Og hvordan bedre å vise folk hvor kul du er som en flash programmerer enn å gjøre dem oppleve det selv? I denne opplæringen vil jeg vise deg hvordan du oppretter en moderne meny med fjærlignende knapper. Vi vil også gjøre det passelig fra xml



Forhåndsvisning

La oss ta en rask titt på hva vi jobber mot:

Trinn 1: Klar dokumentet

Opprett en ny Actionscript 3 flash-fil og angi dimensjonene 600 x 200 piksler. Vi er å sette disse dimensjonene for å ha plass til knappene for å følge musen. Sett framerate til 25 og document til ElasticMenu, en klasse som vi vil skape etter design.

La oss lage en bakgrunn gradient som vil være grunnlaget for vår knappen. Lag et rektangel og gjøre det 150 x 40px. Størrelsen spiller ingen rolle på dette tidspunktet, fordi vi vil endre størrelsen på rektangelet for å matche tekststørrelsen på knappen

Jeg kan høre at du spør. Hvorfor ikke lage et rektangel auto med Sprite.graphics .drawRectangle ()
? Jeg skal vise deg hvorfor jeg valgte denne veien. Årsaken bak gjør en MovieClip på scenen, er at vi faktisk kan skjære gjennom rektangelet å lage en kul cut-out knappen som i denne forhåndsvisningen:

Jeg skal ikke gå inn i hvordan du gjør dette eksempelet her, men denne metoden er bedre i tilfelle du ønsker å krydre opp bakgrunnen for knappen. Det er bare et tips

Trinn 2: Opprette Bakgrunn MovieClip

Velg rektangelet du nettopp opprettet, og trykk på F8 (Endre > Convert to Symbol) for å gjøre bakgrunnsgrafikk og sjekk Export for. Actionscript. Gi denne MovieClip klassenavnet "GradBackground". Vi vil bruke denne klassen navn fra Action

Trinn 3:. XML File

Nå skal vi lage xml fil for å holde vår konfigurasjon. Fra denne filen flash filmen vil få navnet knappen, koblingen plassering og farge. Opprett en ny fil ved siden av FLA kilde og name it menu.xml med følgende:?
≪ xml version = "1.0" encoding = "utf-8" >? < menyen > < knappen > < navn > Hjem < /navn > < url > http: //flash.tutsplus.com< /url > < farge > 0xff0000 < /farge > < /knapp > < knappen > < navn > Om oss < /navn > < url > http: //net.tutsplus.com< /url > < farge > 0xccff00 < /farge > < /knapp > < knappen > < navn > Projects < /navn > < url > http: //vector.tutsplus.com< /url > < farge > 0x446677 < /farge > < /knapp > < knappen > < navn > News < /navn > < url > http: //psd.tutsplus.com< /url > < farge > 0x004488 < /farge > < /knapp > < knappen > < navn > Forum < /navn > < url > http: //photo.tutsplus.com< /url > < farge > 0x2244ff < /farge > < /knapp > < knappen > < navn > Kontakt < /navn > < url > http: //audio.tutsplus.com< /url > < farge > 0x232323 < /farge > < /knapp > < /meny >

Hva skjer her? Vi skaper en < knappen > node for hver knapp. Du kan legge til så mange du trenger, men ikke for mange fordi de ikke vil ha plass til å "være elastisk" :) I hver knapp node er det en navnelapp, en url tag og en fargekode, ganske grunnleggende.

Trinn 4: Begynn Programmering

Nå la oss komme til å bygge selve flash-meny. Opprett en ny Actionscript-fil og gi den navnet ElasticMenu.as. For fart har jeg brukt wildcard * å importere alle klassene i pakken. Etter at du er ferdig med flash-menyen, kan du modifiy importen å bare inkludere det du trenger, for å gjøre filstørrelsen mindre. Lag den vanlige pakken og klassenavn ElasticMenu med de nødvendige variablene:
pakke {import flash.display. *; import flash.text. *; import flash.net. *; import flash.events. *; import flash.utils.Timer; public class ElasticMenu strekker MovieClip {var xml: XML; Var knapper: Array; Var TM: Timer; Var maxdist: Number = 50; }}

xml variabel vil holde selve xml lastet fra menu.xml filen. Knappene variabelen er en matrise som vil holde knappen referanser.

TM er en timer som vil ta seg av selve sjekk for avstand.

maxdist variable vil definere på hvilken avstand knappen vil bryte fra musen og gå tilbake til sin plass

Trinn 5:. XML Lasting og håndtering

Ok, la oss lage konstruktøren funksjon, legge lasteoperasjoner og behandle xml:
offentlig funksjon ElasticMenu () {var req = new URLLoader (); req.addEventListener (Event.COMPLETE, xml_loaded); req.load (ny URLRequest ('menu.xml')); knapper = new Array (); TM = new Timer (40); tm.addEventListener (TimerEvent.TIMER, check_buttons);} private funksjon xml_loaded (e: Hendelses) {xml = XML (e.target.data); createButtons ();}

Hva er det som skjer her? Vi skaper en URLRequest objekt og legge en komplett hendelseshåndterer som vil utløse xml_loaded funksjonen når xml er lastet.

Vi initialisere knapper matrise og tidtakeren, og vi knytte TIMER hendelsen til check_buttons () -funksjonen . Dette er funksjonen som vil sjekke for avstanden av knappene. Når xml er lastet, passerer vi det til xml variabel og bygge knappene med createButtons () -funksjonen, som vi vil skape neste

Trinn 6:. Den createButtons Funksjon

Fortsett med lage knapper og plassere dem på scenen programtically:
offentlig funksjon createButtons () {var sectw = (stage.stageWidth /(xml..button.length () + 1)); for (var i = 0; i < xml..button.length (); i ++) {var m = new ElasticButton (); M, X = sectw + (sectw * i); m.y = stage.stageHeight /2; m.init (xml..button [i]); addChild (m); buttons.push (m); } Tm.start ();}

Ok, så vi definerer den sectw variabel, noe som er scenen delt inn antall knapper pluss én. Hvorfor? Fordi vi vil arrangere på knappene for å være exacly samme avstand fra hverandre og okkupere hele scenebredde. For bedre å forstå dette, se på følgende bilde:

Fordi vi sentre knappene på x og y-aksen, vil de ende opp med å være på lik avstand fra hverandre. Da skaper vi en for loop, insidew som vi definerer hver knapp som en ny ElasticButton klasse, som vi vil kode om kort tid. Vi legger hver knapp på sectw avstand fra hverandre og satt sin y til halve scenen for å sentrere dem. Så vi legge dem til scenen og presse dem inn i knapper array, for senere bruk. Men det er en annen funksjon vi kaller på knappen som vi vil definere i ElasticButton klassen, som vi passerer dagens xml-knappen node

Trinn 7:. Den checkButtons Funksjon

La oss fortsette med den viktigste funksjonen utløses hver 40 miliseconds av timeren:
private funksjons check_buttons (e: Timerevent) {for (VAR bi knapper) {if (knappene [b] .dragging) {knappene [b] .x = mouseX; knappene [b] .Y = mousey; if (knapper [b] .getDistance () > maxdist) {knappene [b] .reset (); }}}}

Ok, la oss raskt forklare hva som skjer her, slik at vi kan gå videre til ElasticButton Klasse:

Først av alt, vi sløyfe gjennom alle knappene i rekken, og for hver av dem vi sjekke om de har en dra eiendom med verdien "true". I utgangspunktet hvis musen er over knappen, og hvis "ja", sjekker vi om getDistance () metoden i ElasticButton klassen er høyere enn maxdist variabel. Hvis det er høyere, kaller vi en reset () -funksjonen på knappen. Vi vet ikke noe ennå om disse funksjonene

Trinn 8:. Gjør ElasticButton Class

OK, endelig den klassen vi har alle har ventet på, knappen klasse. Det er der alle de viktige ting skje: finne ut avstanden, skaper teksten, bakgrunnen og ringer reset () for å gå tilbake knappen sin beliggenhet
pakke {import flash.display. *;. import flash.text. *; import flash.net. *; import flash.events. *; import flash.geom.ColorTransform; import fl.transitions.Tween; import fl.transitions.TweenEvent; importere fl.transitions.easing. *; import fl.motion.Color; public class ElasticButton strekker MovieClip {var opprinnelse: Object; Var tekstfeltet: Textfield; Var tf: tekstformat; Var dregging: Boolean = false; Var bg: Sprite; Var url: String; Var TWX: Tween; Var TWY: Tween; Var padding: Number = 8; Var farge: UINT; Var msk: Sprite; offentlig funksjon ElasticButton () {//gjør ingenting}}}

La meg forklare linjene:

Du vil finne at bortsett fra å importere de vanlige klassene, vi også importere fl.transitions.Tween og TweenEvent , lettelser og fl.motion.Color klasser. Vi trenger de tween klasser å tween filmen tilbake til sin opprinnelse og fargen klasse å farge bakgrunnen for fargen i xml

Vi har et par av variabler her.

Opprinnelsen gjenstand er en gjenstand som vil holde x- og y-posisjonen på knappen. Jeg kunne ha gjort det en flash.geom.Point objekt, men jeg er for lat til å inkludere en annen klasse for 2 variabler!

Vi har en tekstfeltet variabel som vil holde knappen merket tekstfeltet, den tf variabel som er et tekstformat gjenstand for tekst styling, den kjente dra ordentlig, en bg Var som vil være bakgrunnen MovieClip, en streng med url for knappen, to variabler å holde tweens, en padding variabel som vil gjøre knappen litt større, farge gjenstanden og et MSK Var som vil være en maske for MovieClip. Vi trenger dette for å få avrundet hjørne du så i forhåndsvisnings

Trinn 9: init () Funksjon

La oss gjøre det init funksjon, utløst av vår overordnede klassen:
offentlig funksjon init (node) {tekstfeltet = new Textfield (); tf = new tekstformat (); tf.size = 14; tf.font = '_sans'; tf.bold = true; tf.color = 0xFFFFFF; tf.align = TextFormatAlign.CENTER; textfield.defaultTextFormat = tf; textfield.text = node..name; textfield.width = 65; textfield.height = 20; textfield.x = - (textfield.width /2); textfield.y = - (textfield.height /2); textfield.mouseEnabled = false; addChild (tekstfeltet); opprinnelse = new Object (); origin.x = this.x; origin.y = this.y; color = node..color; createBG (); url = node..url; dra = false; this.buttonMode = true; this.addEventListener (MouseEvent.MOUSE_OVER, mouse_over); this.addEventListener (MouseEvent.CLICK, mouse_click);}

Det er mye allerede

Vi skaper tekstfeltet, tilordne det et tekstformat med visse egenskaper (jeg vil ikke komme inn i detaljer her),! sette farge til hvit, fordi bakgrunnene vil tendere til å bli mørkere, vi gir det teksten fra node sendes som en parameter. Ganske standard.

Det er best å skape en bredde og justere teksten til sentrum, slik at ulike ord vil bli vakkert justert. Du må bare sørge for å ikke inkludere et veldig langt ord, eller på knappen vil se stygge!

Neste vi har en interessant plassering av tekstfeltet. Vi setter x minus halvparten av bredden og y til minus halvparten av høyden av tekstfeltet, og dermed justere tekstfeltet nøyaktig i midten. Vi trenger dette for å ha en enhetlig beregning av maksimal avstand.

Vi setter mouseEnabled til false for tekstfeltet, for å deaktivere musen rulle av-knappen. Jeg så for denne eiendommen for en hel dag
da jeg først begynte AS3 :)

Opprinnelsen objekt er initialisert neste, og vi skaper x og y eiendommer med x- og y av dagens MovieClip (den ElasticButton klasse). Når knappen går utover maxdist, vi kommer tilbake knappen til disse opprinnelse poeng

Det er et par flere ting skjer her. Vi holder fargen fra xml node i fargen var, vi holder url av-knappen i url Var amd vi kaller en createBG () -funksjonen som vi ennå ikke kode.

Vi satt å dra til false, buttonMode for gjeldende ElasticButton å true og skape musen over og klikk handlers

Trinn 10:. createBG Funksjon

Denne funksjonen vil ta seg av å gjøre bakgrunnen og tint den i henhold til fargen i xml:
offentlig funksjon createBG () {bg = ny GradBackground (); Var dbpad = padding * 2; bg.width = textfield.width + dbpad; bg.height = textfield.height + dbpad; bg.x = - ((textfield.width + dbpad) /2); bg.y = - ((textfield.height + dbpad) /2); addChild (bg); Var col = ny farge (1,1,1,1); col.setTint (farge, 0,4); bg.transform.colorTransform = col; setChildIndex (bg, 0);}

Her gjør vi en GradBackground klasse, som er MovieClip vi opprettet i fla kilden og gi det klassenavnet GradBackground. Vi setter bredden og høyden på MovieClip til tekstfeltet bredde pluss en variabel dbpad. Du vil merke at jeg definert denne variabelen for fart, slik at jeg ikke skriver (padding * 2). Definere en ny variabel med precomputed dobbel polstring er raskere enn å ringe denne operasjonen mange ganger. Vi må ta vare på CPU også!

Hvorfor får jeg legge en padding variabel? Slik at knappen er større enn tekstfeltet. Se på dette bildet for å få en bedre forståelse:

Jeg er også sentre bg MovieClip som jeg gjorde med tekstfeltet: Jeg setter x minus halvparten av høyden og minus halve bredden på bg MovieClip <. br>

Neste jeg lage en ny farge med standardattributter (rgb og alfa 1) og senere bruke setTint () -funksjonen til å gjøre det til en skygge av xml farge. Fordi Color klasse er en underklasse av ColorTransform klasse, kan vi passere denne fargen direkte til MovieClip transform.colorTransform objektet.

Til slutt setter vi bg MovieClip dybden 0, så alt vil være over bakgrunnen.

Trinn 11: Arrangement Handlers

Jeg vil raskt gå gjennom hendelsesbehandlinger:
privat funksjon mouse_over (e: MouseEvent) {dra = true;} private funksjon mouse_click (e: MouseEvent) {navigateToURL (ny URLRequest (url));}

De hendelsesbehandlinger er ganske enkelt: Jeg satt å dra til true når musen svever over knappen. For et klikk behandleren bruker jeg navigateToURL () -funksjonen til å gå til url spurt. Hvis du bygger en flash område, dette er hvor handlingen for siden endringen ville gå

Trinn 12:. Den getDistance Funksjon

Dette er den viktigste funksjonen i menyen. Husk, vi kaller den getDistance funksjonen for å se om det er større enn maxdist Var så vi kan tilbake knappen. Vi bruker den algebraiske ligningen for Pitagora å finne avstanden mellom 2 poeng:
offentlig funksjon getDistance () {return Math.sqrt ((this.x-origin.x) * (this.x-origin.x) + (this.y-origin.y) * (this.y-origin.y));}

Dette vil gi oss avstanden mellom knappen x og y og opprinnelsen x og y. Det er derfor vi holder opprinnelsen variable

Trinn 13:. Reset Funksjon

Denne funksjonen utløses når avstanden fra origo er for høy. På det tidspunktet tween vi på knappen tilbake til sin opprinnelse:
reset offentlig function () {dra = false; TWX = new Tween (dette, 'x', Elastic.easeOut, this.x, origin.x, 0,4, true); TWY = new Tween (dette, 'y', Elastic.easeOut, this.y, origin.y, 0,4, true);}

Vi setter dra til false og opprette to tweens; en for x og en for y. Vi kunne ha brukt en annen tweening bibliotek, kun brukt en tween og bestått en matrise til tweening funksjon, men den innebygde Tween klasse fra AS3 støtter ikke flere egenskaper, så vidt jeg vet.

Trinn 14: Avrunding knappene

La meg vise deg, som en bonus, hvordan gjøre den første og siste knapp runde, som du så i forhåndsvisningen. Vi skaper en ny funksjon makeStartButton () hvor vi skal bygge den avrundede maske:
offentlig funksjon makeStartButton () {msk = new Sprite (); msk.graphics.beginFill (0x000000,1); msk.graphics.moveTo (0, padding); msk.graphics.curveTo (0, 0, padding, 0); msk.graphics.lineTo ((padding * 2) + textfield.width, 0); msk.graphics.lineTo ((padding * 2) + textfield.width, (padding * 2) + textfield.height); msk.graphics.lineTo (0, (padding * 2) + textfield.height); msk.graphics.lineTo (0, padding); msk.graphics.endFill (); msk.x = bg.x; msk.y = bg.y; addChild (MSK); bg.mask = msk;}

Ok, dette må forklares:

Vi skaper en ny Sprite og bruke den grafiske klasse beginfill () for å lage en fyll, ikke fargen ikke saken. For å forstå hva som skjer La oss se på dette bildet:

Vi bygger avrundet bakgrunn masken og legge den til i displayList, sette den som en maske for bg MovieClip

Trinn 15 : Avrunding den andre knappen

Vi bruker samme framgangsmåte, nå med kurven til høyre:
offentlig funksjon makeEndButton () {var dbpad = padding * 2; msk = new Sprite (); msk.graphics.beginFill (0x000000,1); msk.graphics.lineTo (textfield.width + padding, 0); msk.graphics.curveTo (textfield.width + dbpad, 0, textfield.width + dbpad, padding); msk.graphics.lineTo (dbpad + textfield.width, dbpad + textfield.height); msk.graphics.lineTo (0, dbpad + textfield.height); msk.graphics.lineTo (0, padding); msk.graphics.endFill (); msk.x = bg.x; msk.y = bg.y; addChild (MSK); bg.mask = msk;}

Du vil se at det er den samme teknikken, vi bare gjøre kurven til høyre, og vi legger masken til bg MovieClip

Trinn 16:. The Final Touch

Vi må endre ElasticMenu klassen til å kalle disse to funksjonene på den første og de siste knappene. I createButtons () gjør vi følgende endringer (linje 8 - 13):
offentlig funksjon createButtons () {var sectw = (stage.stageWidth /(xml..button.length () + 1)); for (var i = 0; i < xml..button.length (); i ++) {var m = new ElasticButton (); M, X = sectw + (sectw * i); m.y = stage.stageHeight /2; m.init (xml..button [i]); if (i == 0) {m.makeStartButton (); } If (i == xml..button.length () - 1) {m.makeEndButton (); } AddChild (m); buttons.push (m); } Tm.start ();}

Så hvis variabelen i er 0 (hvis det er den første knappen) eller hvis jeg er xml..button.length () - 1 (hvis det er det siste) vi kaller den respektive funksjon.

Bare husk, hvis du støter på noen feil, at funksjonene vi kaller fra den overordnede klassen, ElasticMenu må være offentlig i ElasticButton klassen, ellers vil du få en feilmelding om at funksjonen ikke finnes!

Det er det! Dette er hele koden for ElasticMenu klassen.
Pakke {import flash.display *; import flash.text. *; import flash.net. *; import flash.events. *; import flash.utils.Timer; public class ElasticMenu strekker MovieClip {var xml: XML; Var knapper: Array; Var TM: Timer; Var maxdist: Number = 50; Var linje: Sprite; offentlig funksjon ElasticMenu () {var req = new URLLoader (); req.addEventListener (Event.COMPLETE, xml_loaded); req.load (ny URLRequest ('menu.xml')); knapper = new Array (); TM = new Timer (40); tm.addEventListener (TimerEvent.TIMER, check_buttons); } Private funksjon xml_loaded (e: Hendelses) {xml = XML (e.target.data); createButtons (); } Offentlig funksjon createButtons () {var sectw = (stage.stageWidth /(xml..button.length () + 1)); for (var i = 0; i < xml..button.length (); i ++) {var m = new ElasticButton (); M, X = sectw + (sectw * i); m.y = stage.stageHeight /2; m.init (xml..button [i]); if (i == 0) {m.makeStartButton (); } If (i == xml..button.length () - 1) {m.makeEndButton (); } AddChild (m); buttons.push (m); } Tm.start (); } Private funksjon check_buttons (e: Timerevent) {for (var bi knapper) {if (knappene [b] .dragging) {knappene [b] .x = mouseX; knappene [b] .Y = mousey; if (knapper [b] .getDistance () > maxdist) {knappene [b] .reset (); .}}}}}}

Og for ElasticButton Klasse:
pakke {import flash.display *; import flash.text. *; import flash.net. *; import flash.events. *; import flash.geom.ColorTransform; import fl.transitions.Tween; import fl.transitions.TweenEvent; importere fl.transitions.easing. *; import fl.motion.Color; public class ElasticButton strekker MovieClip {var opprinnelse: Object; Var tekstfeltet: Textfield; Var tf: tekstformat; Var dregging: Boolean = false; Var bg: Sprite; Var url: String; Var TWX: Tween; Var TWY: Tween; Var padding: Number = 8; Var farge: UINT; Var msk: Sprite; offentlig funksjon ElasticButton () {//gjør ingenting} offentlig funksjon init (node) {tekstfeltet = new Textfield (); tf = new tekstformat (); tf.size = 14; tf.font = '_sans'; tf.bold = true; tf.color = 0xFFFFFF; tf.align = TextFormatAlign.CENTER; textfield.defaultTextFormat = tf; textfield.text = node..name; textfield.width = 65; textfield.height = 20; textfield.x = - (textfield.width /2); textfield.y = - (textfield.height /2); textfield.mouseEnabled = false; addChild (tekstfeltet); opprinnelse = new Object (); origin.x = this.x; origin.y = this.y; color = node..color; createBG (); url = node..url; dra = false; this.buttonMode = true; this.addEventListener (MouseEvent.MOUSE_OVER, mouse_over); this.addEventListener (MouseEvent.CLICK, mouse_click); } Offentlig funksjon createBG () {bg = new GradBackground (); Var dbpad = padding * 2; bg.width = textfield.width + dbpad; bg.height = textfield.height + dbpad; bg.x = - ((textfield.width + dbpad) /2); bg.y = - ((textfield.height + dbpad) /2); addChild (bg); Var col = ny farge (1,1,1,1); col.setTint (farge, 0,4); bg.transform.colorTransform = col; setChildIndex (bg, 0); } Offentlig funksjon getDistance () {return Math.sqrt ((this.x-origin.x) * (this.x-origin.x) + (this.y-origin.y) * (this.y-origin.y )); } Public reset funksjon () {dra = false; TWX = new Tween (dette, 'x', Elastic.easeOut, this.x, origin.x, 0,4, true); TWY = new Tween (dette, 'y', Elastic.easeOut, this.y, origin.y, 0,4, true); } Private funksjon mouse_over (e: MouseEvent) {dra = true; } Private funksjon mouse_click (e: MouseEvent) {navigateToURL (ny URLRequest (this.url)); } Offentlig funksjon makeStartButton () {msk = new Sprite (); msk.graphics.beginFill (0x000000,1); msk.graphics.moveTo (0, padding); msk.graphics.curveTo (0, 0, padding, 0); msk.graphics.lineTo ((padding * 2) + textfield.width, 0); msk.graphics.lineTo ((padding * 2) + textfield.width, (padding * 2) + textfield.height); msk.graphics.lineTo (0, (padding * 2) + textfield.height); msk.graphics.lineTo (0, padding); msk.graphics.endFill (); msk.x = bg.x; msk.y = bg.y; addChild (MSK); bg.mask = msk; } Offentlig funksjon makeEndButton () {var dbpad = padding * 2; msk = new Sprite (); msk.graphics.beginFill (0x000000,1); msk.graphics.lineTo (textfield.width + padding, 0); msk.graphics.curveTo (textfield.width + dbpad, 0, textfield.width + dbpad, padding); msk.graphics.lineTo (dbpad + textfield.width, dbpad + textfield.height); msk.graphics.lineTo (0, dbpad + textfield.height); msk.graphics.lineTo (0, padding); msk.graphics.endFill (); msk.x = bg.x; msk.y = bg.y; addChild (MSK); bg.mask = msk; }}}
Konklusjon

Nå, som var en ganske lang tutorial! Jeg håper jeg ikke kjede noen. Hvis du har noen ideer om hvordan vi kan forbedre menyen, legge dem til kommentarene.

Takk for lesing!