Recreate Cover Flow Effect Bruk av blits og AS3
Del
Del
en
Del
Denne Cyber Monday Envato Tuts + kurs vil bli redusert til bare $ 3. Ikke gå glipp av.
Du har nok sett den "Cover Flow" visning i kraft. Det er over alt på Apples ting. Og du har også sikkert sett en rekke implementasjoner av Cover Flow i Flash. I denne opplæringen, vil du få en mer. Vi vil utnytte de innebygde 3D-mulighetene i Flash Player 10 (som er pre-Stage3D) og bygge vår egen XML-drevet versjon av Cover Flow.
Vi setter opp konstanter å inneholde standardverdiene for hver av disse egenskapene. Disse kan gå med resten av dine egenskaper:
privat statisk konst DEFAULT_CENTER_MARGIN: Number = 60; private static konst DEFAULT_HORIZONTAL_SPACING: Number = 30; private static konst DEFAULT_BACK_ROW_DEPTH: Nummer = 150; private static konst DEFAULT_BACK_ROW_ANGLE: Number = 45; privat statisk konst DEFAULT_VERTICAL_OFFSET: Antall = 0;
I konstruktøren, satt hver av egenskapene til disse standardverdiene (hvis du ikke liker standardverdiene, kan du endre dem, det er en del av grunnen for å sette dem sammen i en lett å finne sted). På denne måten vil vi være sikker på at hver av disse variablene er satt med en passende verdi selv om brukeren aldri spesifisert én
offentlig funksjon Coverflow (w: Antall, h: Number). {_width = W; _height = H; _covers = new Vector. < Cover > (); _centerMargin = DEFAULT_CENTER_MARGIN; _horizontalSpacing = DEFAULT_HORIZONTAL_SPACING; _backRowDepth = DEFAULT_BACK_ROW_DEPTH; _backRowAngle = DEFAULT_BACK_ROW_ANGLE; _verticalOffset = DEFAULT_VERTICAL_OFFSET; _coversContainer = new Sprite (); addChild (_coversContainer); _background = new Shape (); addChildAt (_background, 0); drawBackground (); scrollRect = new rektangel (0, 0, _width, _height); _urlLoader = new URLLoader (); _urlLoader.addEventListener (Event.COMPLETE, onXMLLoad); _urlLoader.addEventListener (IOErrorEvent.IO_ERROR, onXMLLoadError);}
Og med gyldige verdier i tankene, skriver settere og getters (Jeg kommer til å sette disse rett etter vår nåværende settere og getters, rundt linje 89):
offentlig funksjon satt centerMargin (tall: Number): void {if (isNaN (num)) num = DEFAULT_CENTER_MARGIN; _centerMargin = Math.max (0, num);} offentlig funksjon får centerMargin (): Antall {return _centerMargin;} offentlig funksjon satt horizontalSpacing (tall: Number): void {if (isNaN (num)) num = DEFAULT_HORIZONTAL_SPACING; _horizontalSpacing = Math.max (0, num);} offentlig funksjon får horizontalSpacing (): Antall {return _horizontalSpacing;} offentlig funksjon satt backRowDepth (tall: Number): void {if (isNaN (num)) num = DEFAULT_BACK_ROW_DEPTH; _backRowDepth = Math.max (0, num);} offentlig funksjon får backRowDepth (): Antall {return _backRowDepth;} offentlig funksjon satt backRowAngle (tall: Number): void {if (isNaN (num)) num = DEFAULT_BACK_ROW_ANGLE; _backRowAngle = Math.min (90, Math.abs (num));} offentlig funksjon får backRowAngle (): Antall {return _backRowAngle;} offentlig funksjon satt verticalOffset (tall: Number): void {if (isNaN (num)) num = DEFAULT_VERTICAL_OFFSET; _verticalOffset = num;} offentlig funksjon får verticalOffset (): Antall {return _verticalOffset;}
Og til slutt må vi erstatte tallene innbakt i vår layout logikk med disse egenskapene. I layout:
for (var i: UINT = 0, jeg < len; i ++) {dekke = _covers [i]; if (i == _selectedIndex) {cover.rotationY = 0; cover.x = _background.width /2; cover.z = 0; _coversContainer.setChildIndex (dekk, _coversContainer.numChildren-1); } Else if (i < _selectedIndex) {distanceFromCenter = _selectedIndex - i; cover.rotationY = -_backRowAngle; cover.x = ((_background.width /2) - _centerMargin) - (distanceFromCenter * _horizontalSpacing); cover.z = _backRowDepth; _coversContainer.setChildIndex (cover, _coversContainer.numChildren - (distanceFromCenter + 1)); } Else if (i > _selectedIndex) {distanceFromCenter = i - _selectedIndex; cover.rotationY = _backRowAngle; cover.x = ((_background.width /2) + _centerMargin) + (distanceFromCenter * _horizontalSpacing); cover.z = _backRowDepth; _coversContainer.setChildIndex (cover, _coversContainer.numChildren - (distanceFromCenter + 1)); } Cover.y = 250;}
Du kan teste filmen som den er, og ting skal fungere akkurat som de har gjort før. Men du kan også teste disse egenskapene ved å sette dem fra CoverFlowTest. Sett dem slik du vil (faktisk, sørg for å teste de ulovlige verdier, som -200 for centerMargin), for eksempel:
offentlig funksjon CoverFlowTest () {Coverflow = new Coverflow (stage.stageWidth, stage.stageHeight); addChild (Coverflow); coverFlow.backgroundColor = 0x000000; coverFlow.horizontalSpacing = 60; coverFlow.centerMargin = 100; coverFlow.load ("coverFlowImages.xml"); coverFlow.addEventListener (Event.COMPLETE, onCoverFlowLoaded); coverFlow.addEventListener (ProgressEvent.PROGRESS, onCoverFlowProgress);}
Trinn 32: Effektiv Layout
Akkurat nå er våre coverflow fungerer og noe passelig, men bare hvis vi setter verdiene før XML filen lastes. Som det er nå, vil sette egenskapene til enhver etter det resultere i ingen endring.
Dette kan være så enkelt som bare å ringe layout () fra hver av settere. Dette er imidlertid utsatt for ineffektiv bruk av CPU-sykluser. Hvis du trenger å sette alle fem eiendommer i ett slag, vil du ende opp med å jobbe med layout logikk 5 ganger i rad, den første 4 er meningsløst siden du ikke ble ferdig med å sette verdiene til det du måtte. Anmeldelser
Fordi Flash opererer på ramme modell av rendering, hvor kode eksekverer i mellom hver ramme, og deretter skjermen er oppdatert, trenger vi en måte å bare kjøre det oppsettet metoden når scenen er i ferd med å bli gjengitt på neste ramme. Dette kan la oss sette egenskaper så mye som vi liker, men fortsatt bare tegne Coverflow gang per ramme.
Det er en enkel måte å gjøre dette, heldigvis, men det tar litt midlene. Vi må utnytte Render hendelsen. Render Arrangementet vil bli sendt ut av en Displayobject når scenen er i ferd med å bli gjengitt, men før gjengi skjer. Som en bonus, ikke hendelsen ikke ekspedere når Flash Player er minimert, noe som betyr at vi ikke skal sløse sykluser hvis du ikke engang kan se filmen
Implementering av dette er en tre trinns prosess. Første Vi må lytte etter hendelsen. I konstruktøren av Coverflow, legger denne linjen:
this.addEventListener (Event.RENDER, onRender);
Deretter legger lytteren metode:
privat funksjon onRender (e: Hendelses): void {layout ( );}
Yup, det er det ... vi skal bare ringe layout hver gang vi får arrangementet
Til slutt, må vi ringe ugyldig på scenen hver gang vi ønsker Render hendelsen komme vår vei. . Dette betyr at i hvert av settere, må vi legge denne linjen helt til slutt:
if (scene) stage.invalidate ();
Hvis det ikke er scenen, vi ønsker ikke å kalle en Fremgangsmåten og forårsake et nullreferanseobjekt feil. Uansett, hvis det ikke er scenen, så Coverflow objektet er ikke på listen skjerm uansett, så det er ikke poenget i å be om den gjengi hendelsen.
Kallet til ugyldig, derimot, er hvordan vi får RENDER hendelsen til brann. Uten at samtalen, vil vi ikke få arrangementet, selv med en hendelse lytteren. Så trenger vi dette i hvert Legger:
offentlig funksjon satt centerMargin (tall: Number): void {if (isNaN (num)) num = DEFAULT_CENTER_MARGIN; _centerMargin = Math.max (0, num); if (scene) stage.invalidate ();} offentlig funksjon får centerMargin (): Antall {return _centerMargin;} offentlig funksjon satt horizontalSpacing (tall: Number): void {if (isNaN (num)) num = DEFAULT_HORIZONTAL_SPACING; _horizontalSpacing = Math.max (0, num); if (scene) stage.invalidate ();} offentlig funksjon får horizontalSpacing (): Antall {return _horizontalSpacing;} offentlig funksjon satt backRowDepth (tall: Number): void {if (isNaN (num)) num = DEFAULT_BACK_ROW_DEPTH; _backRowDepth = Math.max (0, num); if (scene) stage.invalidate ();} offentlig funksjon får backRowDepth (): Antall {return _backRowDepth;} offentlig funksjon satt backRowAngle (tall: Number): void {if (isNaN (num)) num = DEFAULT_BACK_ROW_ANGLE; _backRowAngle = Math.min (90, Math.abs (num)); if (scene) stage.invalidate ();} offentlig funksjon får backRowAngle (): Antall {return _backRowAngle;} offentlig funksjon satt verticalOffset (tall: Number): void {if (isNaN (num)) num = DEFAULT_VERTICAL_OFFSET; _verticalOffset = num; if (scene) stage.invalidate ();} offentlig funksjon får verticalOffset (): Antall {return _verticalOffset;}
Så nå, hvis vi setter alle 5 eiendommer samtidig, vi kan kalle ugyldig på scenen mer enn en gang, men det er fint, det er ikke til å forårsake problemer. Vi bør få et enkelt RENDER hendelse som et resultat, noe som betyr at vi legger ut Coverflow bare én gang per ramme.
For å teste dette, kan vi sette noen spor i våre metoder, og deretter sette disse egenskapene etter XML har lastet. Først legger et spor melding til onRender:
privat funksjon onRender (e: Hendelses): void {trace ("rendre") layout ();}
Så, i CoverFlowTest, satt alle 5 eiendommer i onCoverFlowLoaded:
privat funksjon onCoverFlowLoaded (e: Hendelses): void {trace ("Coverflow lastet og klar til å gå."); coverFlow.horizontalSpacing = 100; coverFlow.centerMargin = 75; coverFlow.backRowDepth = 300; coverFlow.backRowAngle = 75; coverFlow.verticalOffset = 50;}
Du burde se filmen laste bilder som før, men denne gangen, bildene skal hoppe til en litt annen layout når alle bildene er lastet. Dette beviser at ting fungerer visuelt, men enda viktigere, sjekk utdatapanelet. Du bør se en eneste "render" -melding. Vi kalte stage.invalidate fra de 5 settere, men som resulterte i kun en enkelt RENDER arrangementet, som er det vi er ute etter.
Ta gjerne fjerne spor og oppsettet koden vi nettopp lagt.
Trinn 33: omgruppere
Det er en stund siden jeg har listet opp hele klassekoden. Vårt arbeid har i hovedsak vært i Coverflow. Her er den nåværende tilstand av ting med den klassen.
Pakke com.tutsplus.coverflow {import flash.display *; importere flash.geom. *; import flash.events. *; import flash.net. *; import flash.text. *; import flash.utils. *; public class Coverflow strekker Sprite {private Var _coversContainer: Sprite; private Var _width: Number; private Var _height: Number; private Var _backgroundColor: uint = 0; private Var _background: Shape; private Var _covers. Vector < Cover >; private Var _urlLoader: URLLoader; private Var _xml: XML; private Var _loadCounter: UINT; private Var _bytesPerImage: int; private Var _bytesTotal: int; private Var _selectedIndex: UINT; private Var _centerMargin: Number; private Var _horizontalSpacing: Number; private Var _backRowDepth: Number; private Var _backRowAngle: Number; private Var _verticalOffset: Number; private static konst DEFAULT_CENTER_MARGIN: Number = 60; private static konst DEFAULT_HORIZONTAL_SPACING: Number = 30; private static konst DEFAULT_BACK_ROW_DEPTH: Nummer = 150; private static konst DEFAULT_BACK_ROW_ANGLE: Number = 45; private static konst DEFAULT_VERTICAL_OFFSET: Antall = 0; offentlig funksjon Coverflow (w: Antall, h: Number) {_width = w; _height = H; _covers = new Vector. < Cover > (); _centerMargin = DEFAULT_CENTER_MARGIN; _horizontalSpacing = DEFAULT_HORIZONTAL_SPACING; _backRowDepth = DEFAULT_BACK_ROW_DEPTH; _backRowAngle = DEFAULT_BACK_ROW_ANGLE; _verticalOffset = DEFAULT_VERTICAL_OFFSET; _coversContainer = new Sprite (); addChild (_coversContainer); _background = new Shape (); addChildAt (_background, 0); drawBackground (); scrollRect = new rektangel (0, 0, _width, _height); _urlLoader = new URLLoader (); _urlLoader.addEventListener (Event.COMPLETE, onXMLLoad); _urlLoader.addEventListener (IOErrorEvent.IO_ERROR, onXMLLoadError); this.addEventListener (Event.RENDER, onRender); } Styre offentlig funksjon sett bredde (tall: Number): void {_width = num; _background.width = _width; scrollRect = new rektangel (0, 0, _width, _height); } Overstyre offentlig funksjon get bredde (): Antall {return _width; } Overstyre offentlig funksjon satt høyde (tall: Number): void {_height = num; _background.height = _height; scrollRect = new rektangel (0, 0, _width, _height); } Overstyre offentlig funksjon får høyde (): Antall {return _height; } Offentlig funksjon sette bakgrunnsfarge (val: uint): void {_backgroundColor = val; drawBackground (); for hver (var dekning: Cover i _covers) {cover.backgroundColor = val; }} Offentlig funksjon får bakgrunnsfarge (): uint {return _backgroundColor; } Offentlig funksjon satt centerMargin (tall: Number): void {if (isNaN (num)) num = DEFAULT_CENTER_MARGIN; _centerMargin = Math.max (0, num); if (scene) stage.invalidate (); } Offentlig funksjon får centerMargin (): Antall {return _centerMargin; } Offentlig funksjon satt horizontalSpacing (tall: Number): void {if (isNaN (num)) num = DEFAULT_HORIZONTAL_SPACING; _horizontalSpacing = Math.max (0, num); if (scene) stage.invalidate (); } Offentlig funksjon får horizontalSpacing (): Antall {return _horizontalSpacing; } Offentlig funksjon satt backRowDepth (tall: Number): void {if (isNaN (num)) num = DEFAULT_BACK_ROW_DEPTH; _backRowDepth = Math.max (0, num); if (scene) stage.invalidate (); } Offentlig funksjon får backRowDepth (): Antall {return _backRowDepth; } Offentlig funksjon satt backRowAngle (tall: Number): void {if (isNaN (num)) num = DEFAULT_BACK_ROW_ANGLE; _backRowAngle = Math.min (90, Math.abs (num)); if (scene) stage.invalidate (); } Offentlig funksjon får backRowAngle (): Antall {return _backRowAngle; } Offentlig funksjon satt verticalOffset (tall: Number): void {if (isNaN (num)) num = DEFAULT_VERTICAL_OFFSET; _verticalOffset = num; if (scene) stage.invalidate (); } Offentlig funksjon får verticalOffset (): Antall {return _verticalOffset; } Private funksjon drawBackground (): void {_background.graphics.clear (); _background.graphics.beginFill (_backgroundColor, 1); _background.graphics.drawRect (0, 0, _width, _height); } Private funksjon layout (): void {_selectedIndex = 4; Var len: uint = _covers.length; Var dekke: Cover; Var distanceFromCenter: UINT; for (var i: UINT = 0, jeg < len; i ++) {dekke = _covers [i]; if (i == _selectedIndex) {cover.rotationY = 0; cover.x = _background.width /2; cover.z = 0; _coversContainer.setChildIndex (dekk, _coversContainer.numChildren-1); } Else if (i < _selectedIndex) {distanceFromCenter = _selectedIndex - i; cover.rotationY = -_backRowAngle; cover.x = ((_background.width /2) - _centerMargin) - (distanceFromCenter * _horizontalSpacing); cover.z = _backRowDepth; _coversContainer.setChildIndex (cover, _coversContainer.numChildren - (distanceFromCenter + 1)); } Else if (i > _selectedIndex) {distanceFromCenter = i - _selectedIndex; cover.rotationY = _backRowAngle; cover.x = ((_background.width /2) + _centerMargin) + (distanceFromCenter * _horizontalSpacing); cover.z = _backRowDepth; _coversContainer.setChildIndex (cover, _coversContainer.numChildren - (distanceFromCenter + 1)); } Cover.y = 250; }} Privat funksjon onXMLLoad (e: Hendelses): void {_xml = new XML (_urlLoader.data); Var imageList: XMLList = _xml.image; Var Ilen: uint = imageList.length (); Var imageNode: XML; Var dekke: Cover; for (var i: uint = 0; i < Ilen; i ++) {imageNode = imageList [i]; . Var tittel: String = imageNode @ tittel; dekselet = new Cover (tittel, imageNode, _backgroundColor); _coversContainer.addChild (cover); _covers.push (cover); } oppsett(); _loadCounter = 0; loadNextCover (); } Private funksjon onXMLLoadError (e: IOErrorEvent): void {trace ("Det oppsto en feil under lasting av XML-dokumentet:" + e.text); } Public load funksjon (url: String): void {clearContents (); _urlLoader.load (ny URLRequest (url)); } Private funksjon clearContents (): void {} privat funksjon loadNextCover (): void {var dekselet: Cover = _covers [_loadCounter]; Var src. String = _xml.image [_loadCounter] @ src; cover.load (src); cover.addEventListener (Event.COMPLETE, onCoverLoad); cover.addEventListener (ProgressEvent.PROGRESS, onCoverProgress); } Private funksjon onCoverLoad (e: Hendelses): void {e.target.removeEventListener (Event.COMPLETE, onCoverLoad); _loadCounter ++; if (_loadCounter < _covers.length) {loadNextCover (); } Else {dispatchEvent (ny hendelse (Event.COMPLETE)); }} Privat funksjon onCoverProgress (e: ProgressEvent): void {if (_bytesPerImage == 0) {_bytesPerImage = e.bytesTotal; _bytesTotal = _bytesPerImage * _covers.length; } Var adjustedBytesLoaded: uint = e.bytesLoaded * (_bytesPerImage /e.bytesTotal); Var cumulativeBytesLoaded: uint = (_loadCounter * _bytesPerImage) + adjustedBytesLoaded; dispatchEvent (ny ProgressEvent (ProgressEvent.PROGRESS, falsk, falsk, cumulativeBytesLoaded, _bytesTotal)); } Private funksjon onRender (e: Hendelses): void {layout (); }}}
Trinn 34: Caption
Vi har noen flere ting å rydde opp før vi kommer til animasjon og moro interaktivitet. Vi tar på etiketten. For å få denne rullende, vi trenger bare et tekstfelt. Vi setter opp noen standard styling, og åpne stiler opp for tilpasning i neste trinn.
Først oppretter en Textfield, og legge den til i Coverflow. I Coverflow, sammen med resten av dine egenskaper, skape et Textfield eiendom:
private Var _captionField: Textfield;
Deretter sette den opp i konstruktøren (hvor som helst er greit, men jeg setter det etter alt annet i konstruktør):
_captionField = new Textfield, addChild (_captionField); _ captionField.width = 200; _captionField.height = 50; _captionField.x = (_width - _captionField.width) /2; _captionField.y = _height - 80; _captionField.multiline = true; _captionField.wordWrap = true; Var skriftnavn: String; Var skrifter: Array = Font.enumerateFonts (true); for hver (var font: Font i skrifter) {trace (font.fontName); if (font.fontName.search (/lucida.*grande/i) > -1) {skriftnavn = font.fontName; gå i stykker; }} hvis skriftnavn = "Verdana"; Var format (skriftnavn!): tekstformat = new tekstformat (skriftnavn, 12, 0xFFFFFF); format.align = TextFormatAlign.CENTER; _captionField.defaultTextFormat = format;
Til slutt, i layout, legge inn en linje for å sette teksten i Textfield:
privat funksjon layout (): void {_selectedIndex = 4; Var len: uint = _covers.length; Var dekke: Cover; Var distanceFromCenter: uint for (var i: uint = 0; i < len; i ++) {dekke = _covers [i]; if (i == _selectedIndex) {cover.rotationY = 0; cover.x = _background.width /2; cover.z = 0; _coversContainer.setChildIndex (dekk, _coversContainer.numChildren-1); _captionField.text = cover.caption; //...
Textfield skapningen i konstruktøren er muligens litt skremmende. For det meste, skjønt, det er ganske standard Textfield oppsett, alt gjort gjennom koden. Hvis du aldri har gjort det før, kan du bli overrasket over hvor mange linjer som er nødvendige for å sette opp en Textfield. Dette er typisk; standardTextField i ganske tørt, og vi må sørge for at størrelsen er satt, at det er et flerlinjet tekstfeltet, og at den har en grunnleggende formatet.
Selv om du har skrevet programmatextfields før, "skriftnavn" business kan fortsatt være en overraskelse. Den generelle ideen er at vi setter opp en standardstil, basert på Apples bruk av skrift Lucida Grande som deres system font. Men vi kan ikke være sikre på at brukerne vil ha det skrift (de fleste, om ikke alle, Mac OS X skal, men vi kan ikke være 100% sikker og PC-er er en annen historie). Så får vi en Array med systemskrifter, bruker Font.enumerateFont (sant). Den "ekte" forteller enumerateFont å nummerere systemfontene; ellers nummerer det skriftene emebedded inn i SWF. Dette returnerer en matrise av Font stedene. Vi løkken over at Array, på jakt etter en font med et navn som ligner på "Lucida Grande." Det er et vanlig uttrykk i "søk" samtalen, som bare gir oss en viss fleksibilitet i tilfelle navn skriften er litt annerledes på ett system i motsetning til en annen. Hvis vi finner en match, grip navn skriften og bryte sløyfen. Hvis vi gjør det gjennom løkken uten en kamp, bare bruk "Verdana". Dette gir oss Lucida Grande hvis brukeren har det, og en reserve sans serif font hvis de ikke gjør det
Gå videre og prøve det ut.; du bør se etiketten dukker opp under sentrert element.
Dessuten kan du legge merke til en haug med ekstra spor som viser opp i utdatapanelet. Dette er fra skriften sløyfe i konstruktøren. Vi trenger ikke dette lang sikt, men jeg trodde det ville være nyttig å se disse skriftene blir nummerert. Din produksjonen vil være annerledes, naturlig, avhengig av skrifter som er installert på systemet ditt
Etter at du har sekvensen undersøke skriftnavnene, kan du slette spor (font.fontName.); linje fra konstruktør (linje 74 i oppføringen ovenfor)
Trinn 35:. Aktiver tekst Styling
Nå, hva om du ønsker å tilpasse bildeteksten feltet litt? Det er en rimelig anmodning, og vi har et par alternativer. Det ene er at vi kunne skrive settere og getters for den slags ting vi ønsker å eksponere for ekstern kontroll. Dette kan inkludere ting som muliggjør multiline, justere bredden, sette tekstfarge, sette justere typen, sette skriften, og sette skriftstørrelsen. En god del av denne tilnærmingen er at den holder ting innkapslet og vil sannsynligvis gjøre ting lettere for programmereren som bruker dette Coverflow objektet. Hvis alt du trenger å gjøre er å skrive "coverFlow.fontSize = 16" for å gjøre at en mindre justering, så det er omtrent like enkelt som det blir. Ulempen er at vi trenger å plukke og velge hva som er utsatt, og mer kontroll kan vi tilby mer kode vi må skrive i Coverflow for å imøtekomme det.
En annen tilnærming er å bare eksponere Textfield som en ( read-only) eiendom Coverflow. Dette har i utgangspunktet motsatt pro /con ting som det første alternativet. Det er lett for oss å gjennomføre akkurat nå, og gir full kontroll til sluttbruker; hvis du kan gjøre det til en Textfield, kan du gjøre det på den Coverflow bildetekst. Men tilbakelevering for mye kontroll kan ha katastrofale virkninger. De fleste ville ikke bry virkelig å røre den, men ulykker skjer. Verre, men (etter min mening) er at for å angi størrelsen på bildeteksten font, ender du opp med en ganske detaljert (og helt hypotetisk, mind you):
Var format: tekstformat = coverFlow.captionField.defaultTextFormat; format.fontSize = 16; coverFlow.captionField.defaultTextFormat = format;.
For ikke å nevne at det er en forskjell mellom defaultTextFormat på setTextFormat (), og du bør nok være kjent med hvilken du vil bruke i dette scenariet
Så hvilken er best? I en ideell verden ville jeg å stemme for innkapsling metode der ganske mye hver mulig alternativ er gjort rede for. Men i forbindelse med denne opplæringen, er at mye av repeterende kode. Så, i interesse av å prøve å demonstrere denne teknikken, men fortsatt tillate omfattende tilpasning, vil jeg gjennomføre tre eiendommer for tekst styling, sammen med rett og slett utsette Textfield for mer detaljert styling, som, når det skjer, er alternativ nummer tre.
Hvis du liker tanken på innkapsling og ønsker å eschew avslørende av Textfield til eksterne objekter, så det følgende vil fungere som en guide for hvordan du skal skrive flere settere.
Vi vil legge egenskaper for å stille og få skriftnavn, skriftstørrelse og skriftfarge. Dessuten vil vi legge til en getter (ingen setter) for captionField. Styling egenskaper vil kreve en gjengivelse utsettelse som layoutegenskaper gjorde, samt oppmerksomhet til hvordan du bruker tekstformat stedene. For å starte ting av, erklærer en egenskap til å holde tekstformat objekt:
private Var _captionFormat: tekstformat;
Deretter vil vi skape det objektet i konstruktøren når vi setter opp Textfield: product: [første- linje: 73; høydepunkt: [81,82,83] "> //... for hver (var font: Font i skrifter) {trace (font.fontName); if (font.fontName.search (/lucida.*grande/i ) > -1) {skriftnavn = font.fontName; break;}} if (skriftnavn) skriftnavn = "Verdana";! _captionFormat = new tekstformat (skriftnavn, 12, 0xFFFFFF); _captionFormat.align = TextFormatAlign.CENTER; _captionField. defaultTextFormat = _captionFormat;. //...
Listen bare erstatter den midlertidige "format" variabel fra før med denne egenskapen
Det neste vi kan legge til settere og getters (jeg vil sette disse etter alle de andre settere og getters vi har lagt så langt):
offentlig funksjon satt skriftnavn (navn: String): void {_captionFormat.font = navn; _captionField.defaultTextFormat = _captionFormat; if (scene) stage.invalidate (); } offentlig funksjon får skriftnavn (): String {return _captionFormat.font;} offentlig funksjon sette fontstørrelse (størrelse: Number): void {_captionFormat.size = størrelse; _captionField.defaultTextFormat = _captionFormat; if (scene) stage.invalidate ();} offentlig funksjon får skrift (): Antall {return _captionFormat.size som nummer;} offentlig funksjon sette fontcolor (farge: uint): void {_captionFormat.color = farge; _captionField.defaultTextFormat = _captionFormat; if (scene) stage.invalidate ();} offentlig funksjon får fontcolor (): uint {return _captionFormat.color som uint;}
De er alle like hverandre, den eneste forskjellen er de datatyper og selve tekstformat egenskapene vi påvirke. Legg merke til at vi setter verdien på tekstformat objekt, deretter på nytt at objektet som standardformat for bildeteksten Textfield. Vi gjør dette fordi sette defaultTextFormat lager en kopi av formatet objekt, så selv om vi endrer vår referanse til dette objektet, mister vi henvisningen til den som faktisk setter stiler. Lang historie kort, må vi nullstille defaultTextFormat når som endres.
Men bare setter denne stilen for ny tekst som kommer inn i tekstfeltet. Hvis du vil oppdatere stiler på tekst som allerede finnes på feltet, må vi bruke setTextFormat (). Dette, men viser en tilsvarende gjengivelse problem som før. Hvis vi skulle sette alle de tre styling egenskaper på en gang, har vi ikke nødvendigvis ønsker å på nytt format tre ganger på rad. Så i stedet, kaller vi stage.invalidate (), som, som du husker, til slutt vil fyre av Render arrangementet slik at vi kan endre visningen.
Nå, her er grunnen til at vi ønsket en egen onRender metode hektet opp å gjengi hendelsen, i stedet for bare å henge opp layout metoden direkte til det. Oppsettet metoden vil oppdatere bildeteksten, men siden vi har satt en standard tekstformat, er det ingen grunn til å bruke et tekstformat hver gang layout kalles. Vi vil bare bruke et tekstformat i eksisterende tekst, slik at vi kan holde det ut av layout og putte den i onRender:
privat funksjon onRender (e: Hendelses): void {layout (); _captionField.setTextFormat (_captionFormat);}
Til slutt, må vi utsette tekstfeltet selv. Skriv en siste getter:
offentlig funksjon får captionField (): Textfield {return _captionField;}
Og for å teste alt dette, kan vi oppdatere CoverFlowTest sin onCoverFlowLoaded metode:
privat funksjon onCoverFlowLoaded (e: Hendelses): void {trace ("Coverflow lastet og klar til å gå."); coverFlow.horizontalSpacing = 100; coverFlow.centerMargin = 75; coverFlow.backRowDepth = 300; coverFlow.backRowAngle = 75; coverFlow.verticalOffset = 50; coverFlow.fontName = "Courier"; coverFlow.fontSize = 24; coverFlow.fontColor = 0xff0000;}
Kjør den, og når bildene all last og layouten endres, vil du se endringen bildetekst stil, så vel. Føl deg fri til å fjerne disse linjene på dette punktet
Trinn 36:. Vertikal posisjon
Du vil ha lagt merke til at bildeteksten ikke beveger seg med Covers når de justerer sine vertikale offset.
Som du vet, la vi en verticalOffset eiendom noen skritt tilbake, og vi har lagt det til standardverdien på 250 når du plasserer våre Cover stedene. Hvor kommer det 250 kommer fra? Jeg trakk det nummeret ut av luften som noe som fungerer for nå.
Vi kan nå bruke litt logikk vertikal plassering av raden. Vi kan bare låse den til bunns med en forhåndsdefinert margin. Så, i layout, ta ut den linjen som leser cover.y = 250; og erstatte den med:
cover.y = _background.height - 90 + _verticalOffset;
I Apple Coverflow, nederst på rad med Covers er tilsvarende låst til nedre kant av utsikten, men de også endre størrelsen deksler basert på hvor høy utsikten er. Vi hopper det litt av logikk, men det ville være en interessant øvelse hvis du har feber som bare kan kureres med mer Coverflow gang denne opplæringen er over.
Men vi er fortsatt ikke ferdig med vår logikk. Vi vil bruke en tekst piksel margin mellom nedre kant av flyten og bildetekst. Så det står til grunn at vi får lyst til å flytte bildeteksten feltet når du kjører layout, i tilfelle høyden er endret. Legg denne linjen etter løkken i layout:
_captionField.y = _background.height - 80 + _verticalOffset;
For referanse hele metoden bør se slik ut:
privat funksjon layout (): void {_selectedIndex = 4; Var len: uint = _covers.length; Var dekke: Cover; Var distanceFromCenter: uint for (var i: uint = 0; i < len; i ++) {dekke = _covers [i]; if (i == _selectedIndex) {cover.rotationY = 0; cover.x = _background.width /2; cover.z = 0; _coversContainer.setChildIndex (dekk, _coversContainer.numChildren-1); _captionField.text = cover.caption; } Else if (i < _selectedIndex) {distanceFromCenter = _selectedIndex - i; cover.rotationY = -_backRowAngle; cover.x = ((_background.width /2) - _centerMargin) - (distanceFromCenter * _horizontalSpacing); cover.z = _backRowDepth; _coversContainer.setChildIndex (cover, _coversContainer.numChildren - (distanceFromCenter + 1)); } Else if (i > _selectedIndex) {distanceFromCenter = i - _selectedIndex; cover.rotationY = _backRowAngle; cover.x = ((_background.width /2) + _centerMargin) + (distanceFromCenter * _horizontalSpacing); cover.z = _backRowDepth; _coversContainer.setChildIndex (cover, _coversContainer.numChildren - (distanceFromCenter + 1)); } Cover.y = _background.height - 90 + _verticalOffset; } _captionField.y = _background.height - 80 + _verticalOffset;}
Men det er én gjenværende oppgave. Hvis bredden eller høyden få endret, skal vi kalle layout igjen. Dette vil være så enkelt som å lage en annen oppfordring til stage.invalidate i bredde og høyde settere
styre offentlig funksjon sett bredde (tall: Number):. Void {_width = num; _background.width = _width; scrollRect = new rektangel (0, 0, _width, _height); if (scene) stage.invalidate ();} overstyre offentlig funksjon get bredde (): Antall {return _width;} overstyre offentlig funksjon satt høyde (tall: Number): void {_height = num; _background.height = _height; komme tilbake; komme tilbake; komme tilbake;