In deze zelfstudie maken we een herbruikbare countdown-timer met een dynamische streefdatum die kan worden ingesteld via XML. We animeren de nummers die naar beneden klappen in de stijl van een oud statusbord van een luchthaven of treinstation. We behandelen de code, het maken van afbeeldingen en animaties.
Opnieuw gepubliceerde zelfstudieOm de paar weken bekijken we enkele van onze favoriete lezers uit de geschiedenis van de site. Deze tutorial werd voor het eerst gepubliceerd in mei 2010.
Maak een nieuw Flash-bestand (Actionscript 3) met deze instellingen: 500x300, zwarte achtergrond en 30 fps.
Maak een nieuwe MovieClip met de naam 'digit_bottom' en teken hier een afgeronde rechthoek van ongeveer 36px breed bij 50px hoog. (Een snelle manier om een rechthoek met precieze dimensies te tekenen, is door het gereedschap Rechthoek te selecteren en met Alt op het werkgebied te klikken.)
Geef de rechthoek een verloopvulling van # 111111 (boven) naar # 333333 (onder) en een omtrek van 2 px gekleurd # 333333.
Plaats de rechthoek zo dat het registratiepunt van de MovieClip (de kleine '+') precies halverwege tussen de boven- en onderkant en de linkerrand ligt. Als u uw rechthoek 50px groot hebt gemaakt, moet de y -waarde -25 zijn.
Maak een nieuwe laag en voeg een dynamisch tekstveld toe met de naam 't_num'. Kies een lettertype met een luchthaven- of treinstationgevoel (zoals Helvetica, DIN of Interstate). Ik gebruik Helvetica Bold.
Stel de Alineaopmaak in op gecentreerd en onthoud dat u de lettertypen insluit voor de nummers 0-9.
Plaats het tekstveld zodat het gecentreerd is op de achtergrondrechthoek.
We gaan deze MovieClip gebruiken als basis voor een andere afbeelding, dus neem even de tijd om er zeker van te zijn dat deze er goed uitziet.
Maak een nieuwe laag op de tijdlijn van de digit_bottom MovieClip en noem het 'masker'. Kopieer de afgeronde rechthoek en plak op zijn plaats op de masker laag (Bewerken> Plakken op zijn plaats of Command-Shift-V).
Selecteer de bovenste helft van de maskerrechthoek en verwijder deze.
Klik met de rechtermuisknop op de masker laag, kies Masker en zorg ervoor dat alle onderliggende lagen worden gemaskeerd.
Ga naar de bibliotheek, dupliceer de digit_bottom MovieClip en noem de nieuwe kopie 'digit_top'.
Deze MovieClip zal vrijwel identiek zijn aan de digit_bottom clip, behalve dat het masker de bovenste helft van de afbeeldingen toont in plaats van de onderkant.
Verwijder de afbeeldingen die momenteel op de masker laag. Kopieer de afgeronde rechthoek en plak nogmaals op zijn plaats op de masker laag. Selecteer deze keer de onderste helft en verwijder deze.
De enige andere aanpassing die u hier wilt doen, is de kleur van de tekst en de arcering van de achtergrond afgeronde rechthoek aan te passen. Ik heb de afbeeldingen in mijn gemaakt digit_top clip een beetje donkerder om licht te simuleren dat van boven komt.
Maak een nieuwe MovieClip met de naam 'Digit'. Sleep in de digit_top en digit_bottom MovieClips en plaats ze beide op 0,0. Geef ze de instantienamen 'top1' en 'bottom1'.
Kopieer nu beide MovieClips (digit_top en digit_bottom), maak een nieuwe laag en plak op elk exemplaar. Noem de nieuwe kopieën 'top2' en 'bottom2'.
Je zou nu 4 MovieClips in je moeten hebben Cijfer MovieClip: 2 exemplaren van digit_top en 2 exemplaren van digit_bottom. Ik zal uitleggen waarom we dit in de volgende stap zo opzetten.
We moeten een beetje animatietruc doen om het gewenste flipping numbers-effect te krijgen. Bekijk het onderstaande schema van onze Cijfer MovieClip (ik geef het weer in 3D, zodat je de lagen beter kunt zien):
We beginnen met de bottom2 clip ondersteboven gekopieerd (met de eigenschap scaleY) en achter de top2 klem. Op dit punt zijn de 2 clips die zichtbaar zijn top2 en bottom1. De cijfers op deze twee clips komen met elkaar overeen, dus vormen ze een volledig cijfer.
Nu gaan we naar beneden top2 clip naar het midden van het cijfer. Op dit punt is scaleY nul, dus de clip is niet zichtbaar. Tegelijkertijd gaan we ook de bottom2 clip, maar deze gaan we helemaal naar beneden. Omdat het achter zit top2, het wordt pas weergegeven als het halverwege voorbij is. Nu zijn de 2 zichtbare clips top 1 en bottom1. De nummers op deze twee clips komen niet overeen, maar dat is goed, want deze stap duurt slechts een kort moment.
De top2 clip blijft in het midden als bottom2 blijft helemaal dalen tot op de bodem. Zodra het op zijn plaats zit, worden de nummers op de zichtbare clips weergegeven (top 1 en bottom2) opnieuw overeenkomen om een volledig cijfer te vormen.
Op dit punt zullen we relayer en reset de posities van de 2 verborgen clips om klaar te zijn voor de volgende flip. Let op hoe de clips zich in dezelfde positie bevinden als stap 1, alleen omgekeerd.
Nu hebben we het individu Cijfer MovieClip opgezet, laten we de klok bouwen.
Maak een nieuwe MovieClip op het podium genaamd 'Clock' met de instantienaam 'clock'. Plaats binnen de nieuwe MovieClip 9 exemplaren van je Cijfer Filmclip; 2 voor seconden, 2 voor minuten, 2 voor uren en 3 voor dagen. Geef elk cijfer een instantienaam. Van links naar rechts noem ze 'digit0', 'digit1', 'digit2', enzovoort.
Voeg wat dubbele punten toe om de MovieClips en labels voor elke sectie te scheiden. Het ontwerp is aan jou. Ik heb een donkere afgeronde rechthoek toegevoegd als achtergrond voor mijn klok.
Voeg ten slotte een dynamisch tekstveld toe met de naam 't_date'. Hier laten we de doeldatum zien waarop de klok aftelt. Vergeet niet om het lettertype voor dit tekstveld in te sluiten als u geen systeemlettertype gebruikt.
Maak een nieuw Actionscript-bestand met de naam 'Digit.as' en voeg deze code toe om de lege shell voor de klasse te maken:
pakket import flash.display.MovieClip; public class Digit breidt MovieClip uit private const TOP: int = 0; private const BOTTOM: int = 1; private var _currentDigit: Array; private var _nextDigit: Array; privévar_nummer: String = "0"; // CONSTRUCTOR public function Digit () _currentDigit = new Array (top1, bottom1); _nextDigit = new Array (top2, bottom2);
Dit doet nog niet veel. We hebben een aantal arrays om de 2 sets te bewaren digit_top en digit_bottom Filmclips. Ik heb 2 constanten ingesteld, TOP en BOTTOM om de bovenste en onderste clips binnen die arrays bij te houden. De _aantal variabele bevat het cijfer dat op een bepaald moment wordt weergegeven.
(Opmerking: ik gebruik het onderstrepingsteken in mijn variabelenamen om privévariabelen aan te geven.)
Vind je Cijfer MovieClip in de bibliotheek en wijs deze klasse eraan toe in de koppelingsinstellingen.
We gaan de TweenLite-bibliotheek gebruiken om ons te animeren Cijfer Filmclip.
Download hier de AS3-versie van de TweenLite-bibliotheek.
Plaats de map 'com' in dezelfde map als uw hoofd Flash-bestand (of in uw bronpad, als u een ander klassenpad heeft ingesteld).
Voeg deze twee regels toe bovenaan je Cijfer klasse, net onder de import van MovieClip:
import com.greensock. * import com.greensock.easing. *
We gaan amper op zoek naar de oppervlakte van wat TweenLite in deze zelfstudie kan doen. Raadpleeg de TweenLite-documentatie voor meer informatie.
Voeg deze functie toe aan uw Cijfer klasse:
publieke functie flipTo (num: String): void _number = num; _nextDigit [TOP] .t_num.text = num; _nextDigit [BOTTOM] .t_num.text = num; // draai de bovenkant van het cijfer naar beneden tot halverwege TweenLite.to (_currentDigit [TOP], .15, scaleY: 0, ease: Linear.easeNone); // draai het volgende cijfer onderaan naar beneden TweenLite.to (_nextDigit [BOTTOM], .3, scaleY: 1, onComplete: flipComplete, ease: Bounce.easeOut);
Dit is wat er gebeurt, regel voor regel:
Bekijk het schema in stap 8 nog een keer als je hier verward bent over de animatie.
Voeg deze functie toe aan de Cijfer klas net onder de flipTo functie:
private function flipComplete (): void // swap digits var next: Array = _currentDigit; _currentDigit = _nextDigit; _nextDigit = volgende; // reset layering reset ();
Zodra de flipanimatie is voltooid, voeren we deze functie uit. Het ruilt de _currentDigit en _nextDigit arrays. Nadat dat is gedaan, roept het een functie met de naam 'reset' op om de cliplaag en de posities voor de volgende flip opnieuw in te stellen. Laten we die functie nu schrijven.
Voeg deze functie toe aan de Cijfer klasse:
persoonlijke functie reset (): void addChild (_nextDigit [BOTTOM]); addChild (_currentDigit [TOP]); // klap de volgende bodem omhoog om achter de huidige top te staan _nextDigit [BOTTOM] .scaleY = -1; _nextDigit [TOP] .scaleY = 1;
De eerste twee regels in deze functie plaatsen de _nextDigit BOTTOM en vervolgens de _currentDigit TOP naar de top van de displaylijst. Ik gebruik meestal gewoon addChild () om dit te doen omdat het minder typen vereist dan het gebruik van setChildIndex ().
Nadat de clips opnieuw zijn gelaagd, stellen we de scaleY-eigenschappen in zodat ze klaar zijn voor de volgende omkering. Dit betekent veranderen _nextDigit [BOTTOM] van 1 tot -1 en _nextDigit [TOP] van 0 tot 1.
Nogmaals, bekijk het schema in stap 8 als je verdwaalt.
Een ding dat we vergaten te doen, is de clips correct plaatsen voor de eerste flip-animatie. We kunnen dat eenvoudig doen door een oproep toe te voegen aan de reset function right in de Digit class constructor:
// CONSTRUCTOR public function Digit () _currentDigit = new Array (top1, bottom1); _nextDigit = new Array (top2, bottom2); reset ();
Een laatste ding dat we in onze Digit-klasse nodig hebben, is een manier om toegang te krijgen tot het private _aantal variabele van buiten de klas. We voegen een eenvoudige accessor-functie toe:
public function get number (): String return _nummer;
Maak een nieuw ActionScript-bestand met de naam 'Clock.as'. Plak in deze code:
pakket import flash.display.MovieClip; import flash.events.TimerEvent; import flash.media.Sound; import flash.utils.Timer; public class Clock breidt MovieClip uit private var _clockTimer: Timer; private var _targetDate: Date; // CONSTRUCTOR public function Clock ()
Nog niet veel hier. Gewoon enkele van de klassen importeren die we nodig hebben. Ik heb ook een aantal privévariabelen. _clockTimer telt de seconden af voor ons, en _streefdatum zal de datum houden waarop we aftellen.
Voeg deze functie toe aan de klokklasse net onder de constructor:
// stel de streefdatum in en start de countdown-timer public function set (date: Date): void _targetDate = date; _clockTimer = new Timer (1000) // vink elke seconde (1000 milliseconden) _clockTimer.addEventListener (TimerEvent.TIMER, update) aan; _clockTimer.start (); / / toon de streefdatum boven de klok t_date.text = _targetDate.toLocaleString (). toUpperCase (); // update de klok eenmaal hier, zodat deze begint met de juiste tijd update ();
Dit is de functie die we zullen gebruiken om de streefdatum voor de klok in te stellen. Het accepteert een datum (natuurlijk) en wijst dat toe aan de _streefdatum variabel. Vervolgens maakt het onze _clockTimer. De _clockTimer zal de bijwerken functioneer één keer per seconde om de cijfers bij te werken.
Nadat de timer is gestart, stelt de functie de t_date tekst met de streefdatum. De toLocaleString () -functie zorgt ervoor dat de datum wordt weergegeven in de lokale tijdzone van de gebruiker.
De laatste regel van deze functie roept bijwerken eenmaal om de klok op de juiste tijd in te stellen. Anders zou het "000 00:00:00" gedurende één seconde weergeven tot de eerste timergebeurtenis.
Deze functie is een beetje lang omdat het meeste werk wordt gedaan. Voeg het toe aan je klokklasse:
persoonlijke functie-update (e: TimerEvent = null): void var now: Date = new Date (); // haal de huidige tijd op // vind het verschil (in ms) tussen het doel en nu var diff: Number = _targetDate.valueOf () - now.valueOf (); if (diff <=0) // TIME'S UP! // do something cool here _clockTimer.stop(); _clockTimer.removeEventListener(TimerEvent.TIMER, update); diff = 0; // convert to seconds diff = Math.round(diff/1000); // number of days var days:int = Math.floor(diff/ (24 * 60 * 60)); diff -= days*(24 * 60 * 60 ); // number of hours var hours:int = Math.floor(diff / (60 * 60)) diff -= hours*60 * 60; // number of minutes var min:int = Math.floor(diff/ 60); diff -= min*60; // seconds are all that remain var sec:int = diff; // create an array of strings to hold the number for each value var diffArr:Array = new Array(String(days), String(hours), String(min), String(sec)); var diffString:String = "" var len:int = 3; // the first value (days) has 3 digits. All the rest have 2 for each(var s:String in diffArr) // pad the string with a leading zero if needed while(s.length < len) s = "0"+s; len = 2; // all the other values are 2 digits in length diffString += s; // add the padded string to the diffString // go through each character in the diffString and set the corresponding digit for(var i:int = 0; i< diffString.length; i++) if(diffString.substr(i, 1) != this["digit"+i].number) this["digit"+i].flipTo(diffString.substr(i, 1));
Deze functie accepteert een TimerEvent als parameter. De standaardwaarde voor deze parameter is nul. Dit stelt ons in staat om de functie aan te roepen zonder een parameter te verzenden, zoals we in de reeks functie.
De eerste regel van deze functie krijgt de huidige datum en tijd als een object Date. Vervolgens vinden we het verschil tussen de huidige datum en de streefdatum (regel 37). Als het verschil 0 of minder is, is het voorbij de streefdatum, dus stoppen we het _clockTimer (regels 38-44).
Omdat het tijdsverschil tussen nu en het doel wordt berekend in milliseconden, moeten we dat omzetten in een mooie leesbare weergave van dagen, uren, minuten en seconden (regels 46-62). De wiskunde is hier vrij eenvoudig, zolang je weet dat er 1000 milliseconden zijn in een seconde, 60 seconden in een minuut, 60 minuten in een uur en 24 uur in een dag.
Op regel 65 slaan we al die waarden op als elementen in een array. Vanaf regel 68 doorlopen we elk element en voegen het toe aan een tekenreeks met de naam 'diffString'. Terwijl we dit doen, voegen we waar nodig ook nullen toe (regel 71). Dus als onze waarden voor de klok waren 30 dagen, 5 uur, 56 minuten en 6 seconden de diffString zou er als volgt uitzien: "030055606".
Het laatste wat deze functie doet is doorlopen van de karakters in de diffString (met behulp van de methode charAt ()). Voor elk teken in de reeks controleren we of dit afwijkt van het getal dat momenteel wordt weergegeven op het overeenkomstige cijfer. Dit is gemakkelijk vanwege de manier waarop we onze cijferinstanties hebben genoemd. Als het nummer niet hetzelfde is als het nummer dat momenteel wordt weergegeven, vertellen we dat cijfer om naar het nummer in de diffString.
Zoek (of creëer) een goed tikkend geluid dat wordt afgespeeld telkens wanneer de klok wordt bijgewerkt. Importeer het in de bibliotheek van uw Flash-bestand en stel de klassenaam in op TickSound in de koppelingsinstellingen.
Voeg de toe _tickSound variabel naar de bovenkant van uw klokklasse net onder de twee andere variabelen:
private var _clockTimer: Timer; private var _targetDate: Date; private var _tickSound: Sound = new TickSound ();
En speel het geluid in de bijwerken functie:
_tickSound.play ();
Onze afteltimer is voltooid, we hebben alleen een manier nodig om de streefdatum in te stellen. Maak een nieuw Actionscript-bestand met de naam 'Main.as' met deze code:
pakket import flash.display.MovieClip; public class Main breidt MovieClip uit public function Main () // stel de streefdatum in voor de klok var targetDate: Date = new Date (); targetDate.setTime (Date.UTC (2010, 4, 28, 20, 00)); clock.set (targetDate);
Dit alles is ingesteld de streefdatum voor de klokinstantie in het werkgebied. Ik gebruik setTime () en Date.UTC () om de datum in Universal Timecode om te zetten. Op deze manier is de datum correct wanneer deze wordt omgezet naar de lokale tijd op de computer van de gebruiker. Vergeet ook niet dat de maanden op nul gebaseerd zijn. Dus de maand 4 is eigenlijk mei, niet april.
Zet in je Flash-bestand de klasse Document op 'Main'.
Als je opfrissing nodig hebt bij het gebruik van de documentklasse, bekijk dan deze snelle tip.
Test je film nu en alles zou moeten werken. Probeer de streefdatum in de hoofdklasse te wijzigen en zie hoe het aftellen verandert.
Een mogelijk nadeel van hoe we dit hebben ingesteld, is dat de streefdatum hard gecodeerd is in onze SWF. Dat is prima, maar het zou wel cool zijn als we de datum dynamisch konden laden, zodat we het aftellen voor verschillende dingen opnieuw konden gebruiken.
Laten we eens kijken wat we daaraan kunnen doen ...
Maak een nieuw XML-bestand in dezelfde map als uw Flash-bestand met de naam 'targetDate.xml' (een XML-bestand is gewoon een gewoon tekstbestand). Voeg dit toe aan het XML-bestand:
2011 3 25 20 21
Het gebruik van dit formaat voor onze streefdatum is behoorlijk opgeblazen (er is meer mark-up dan er daadwerkelijke gegevens zijn), maar het zal de dingen heel duidelijk houden voor de doeleinden van deze tutorial.
Laten we nu een paar wijzigingen aanbrengen in onze hoofddocumentklasse. Vervang alles in dat bestand door deze code:
pakket import flash.display.MovieClip; import flash.net.URLLoader; import flash.net.URLRequest; import flash.events.Event; public class Main breidt MovieClip uit // CONSTRUCTOR public function Main () // laad de XML var xmlLoader: URLLoader = new URLLoader (); xmlLoader.addEventListener (Event.COMPLETE, onDataLoaded); xmlLoader.load (nieuwe URLRequest ("targetDate.xml"));
U zult merken dat we enkele extra klassen hebben geïmporteerd om ons te helpen het XML-bestand te laden. In de constructorfunctie maken we een nieuwe URLLoader-instantie om het bestand voor ons te laden. We voegen een gebeurtenislistener toe die een functie met de naam 'onDataLoaded' zal aanroepen wanneer het bestand klaar is met laden.
Voeg deze functie toe aan de hoofdklasse:
private function onDataLoaded (e: Event): void var xml: XML = new XML (e.target.data); var targetDate: Date = new Date (); targetDate.setTime (Date.UTC (int (xml.year), int (xml.month), int (xml.day), int (xml.hour), int (xml.minute))); clock.set (targetDate);
Deze functie maakt een nieuw XML-object uit het bestand dat we hebben geladen. Vervolgens maken we een nieuw Date-object uit de waarden in de XML. We gebruiken opnieuw setTime () en Date.UTC () om de datum naar Universal Timecode om te zetten. De laatste regel is hetzelfde als voorheen, het verzendt alleen de doeldatum naar onze klokinstantie.
Dat is het zo'n beetje voor deze. Er zijn een aantal verbeteringen die je misschien wel wilt maken:
Succes! Zoals altijd, plaats een reactie en laat me weten wat je ervan vindt.