<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Flexmaniak.pl &#187; preloader</title>
	<atom:link href="http://blog.flexmaniak.pl/tag/preloader/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.flexmaniak.pl</link>
	<description>Flex, Papervision3D, PHP, Symfony</description>
	<lastBuildDate>Sun, 02 Oct 2011 08:36:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Custom Preloader</title>
		<link>http://blog.flexmaniak.pl/actionscript/custom-preloader</link>
		<comments>http://blog.flexmaniak.pl/actionscript/custom-preloader#comments</comments>
		<pubDate>Tue, 17 Nov 2009 17:35:33 +0000</pubDate>
		<dc:creator>damian</dc:creator>
				<category><![CDATA[ActionScript]]></category>
		<category><![CDATA[custom preloader]]></category>
		<category><![CDATA[Flex Halo]]></category>
		<category><![CDATA[preloader]]></category>

		<guid isPermaLink="false">http://blog.na14.pl/wordpress/?p=115</guid>
		<description><![CDATA[W tym wpisie przedstawię jak w prosty sposób dodać własny preloader do naszej aplikacji, pozbywając się domyślnego &#8211; moim zdaniem brzydkiego :) &#8211; preloadera. Na początek spójrzmy jak będzie wyglądał nasz preloader. Aby osiągnąć taki cel musimy: Stworzyć klasę która dziedziczy po DownloadProgressBar lub implementuje IPreloaderDisplay Zaimplementować w niej odpowiednie metody Dodać nasz preloader do [...]]]></description>
			<content:encoded><![CDATA[<p>W tym wpisie przedstawię jak w prosty sposób dodać własny preloader do naszej aplikacji, pozbywając się domyślnego &#8211; moim zdaniem brzydkiego :) &#8211; preloadera.</p>
<p><span id="more-115"></span></p>
<p>Na początek spójrzmy jak będzie wyglądał <a title="Custom preloader" href="http://blog.na14.pl/examples/sphere/bin/panorama_sphere.html" target="_blank">nasz preloader.</a></p>
<p>Aby osiągnąć taki cel musimy:</p>
<ol>
<li>Stworzyć klasę która dziedziczy po DownloadProgressBar lub implementuje IPreloaderDisplay</li>
<li>Zaimplementować w niej odpowiednie metody</li>
<li>Dodać nasz preloader do aplikacji</li>
</ol>
<p>Najłatwiej będzie zacząć od końca. Aby dodać nasz preloader do aplikacji, należy go wpisać w jej tagu.</p>
<pre class="brush:xml">&lt;mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" preloader="my.loader.MyPreloader"&gt;</pre>
<p>Jak widać mój preloader znajduje się w pakiecie <em>my.loader</em> i nazywa się <em>MyPreloader</em>. W moim przypadku dziedziczy on po klasie <em>Sprite</em>, tak żebym mógł po nim rysować i implementuje interfejs <em>IPreloaderDisplay</em>.</p>
<pre class="brush:js">package my.loader {
  public class MyPreloader extends Sprite implements IPreloaderDisplay {
  }
}</pre>
<p>Gdy tworzymy klasę dziedziczącą po <em>Sprite </em>i implementującą <em>IPreloaderDisplay</em>, to otrzymujemy pakiet wygenerowanych funkcji. Wiekszość z nich możemy usunąć i zostawić:</p>
<pre class="brush:js">        private var _backgroundColor	: uint = 0x000000;
        private var _stageHeight		: Number = 1;
        private var _stageWidth			: Number = 1;

        public function set backgroundAlpha(alpha:Number):void{}
        public function get backgroundAlpha():Number { return 1; }

        public function set backgroundColor(color:uint):void { _backgroundColor = color; }
        public function get backgroundColor():uint { return _backgroundColor; }

        public function set backgroundImage(image:Object):void {}
        public function get backgroundImage():Object { return null; }

        public function set backgroundSize(size:String):void {}
        public function get backgroundSize():String { return "auto"; }

        public function set stageHeight(height:Number):void { _stageHeight = height; }
        public function get stageHeight():Number { return _stageHeight; }

        public function set stageWidth(width:Number):void { _stageWidth = width; }
        public function get stageWidth():Number { return _stageWidth; }</pre>
<p>Dodatkowo musimy zmodyfikowac metody <em>set preloader </em>oraz<em> initialize</em><em>. </em>W metodzie <em>set preloader </em>musimy ustawić eventy dla preloadera.</p>
<pre class="brush:js">    private var _preloader			: Sprite;

    public function set preloader(value:Sprite):void {
            _preloader = value;

            value.addEventListener(ProgressEvent.PROGRESS, progressHandler);
            value.addEventListener(Event.COMPLETE, completeHandler);

            value.addEventListener(FlexEvent.INIT_PROGRESS, initProgressHandler);
            value.addEventListener(FlexEvent.INIT_COMPLETE, initCompleteHandler);
        }</pre>
<p>W metodzie<em> initialize </em>wypełniam tło białym prostokątem, wczytuje plik loga oraz inicjuje <em>Timer</em>, który będzie wywoływany co 50ms, aby update&#8217;ować stan preloadera.</p>
<pre class="brush:js">        public function initialize():void {
		//Wypełnienie tła
		graphics.beginFill( _backgroundColor, 1);
 		graphics.drawRect( 0, 0, stageWidth, stageHeight);
		graphics.endFill();

                loadingImage = new flash.display.Loader();
		loadingImage.contentLoaderInfo.addEventListener( Event.COMPLETE, loader_completeHandler); //metoda wywołana jak obrazek sie wczyta
		loadingImage.load(new URLRequest("../assets/logo.jpg")); // Scieżka do obrazka
        }</pre>
<p>Po wczytaniu obrazka umieszczam go na środku preloadera, zaś label z wartością procentową (początkowo równą 0) umieszczam zaraz pod nim.</p>
<pre class="brush:js">        private var _timer 				: Timer;

        private function loader_completeHandler(event:Event):void
        {
            addChild(loadingImage);
            loadingImage.x = stage.fullScreenWidth / 2 - loadingImage.width / 2;
            loadingImage.y = stage.fullScreenHeight / 3 - loadingImage.height / 2;

	    loadingText = new TextField();
	    loadingText.width = 20;
	    loadingText.height = 20;
	    loadingText.autoSize = TextFieldAutoSize.CENTER;
	    loadingText.text = "0";
	    loadingText.textColor = 0x0000ff;
    	    loadingText.x = stage.fullScreenWidth / 2 - loadingText.width / 2;
	    loadingText.y = loadingImage.y + loadingImage.height + 20;
	    addChild(loadingText);

            _timer = new Timer(50);
            _timer.addEventListener(TimerEvent.TIMER, timerHandler);
            _timer.start();
        }</pre>
<p>Timer, który zainicjowaliśmy w metodzie <em>initialize</em>, ma za zadanie odświeżenie labela oraz obrysowanie go paskami widocznymi na przykładzie, do którego link podałem powyżej.</p>
<pre class="brush:js">        private var _fractionLoaded 	: Number = 0;
        private var _IsInitComplete		: Boolean = false;

        private function timerHandler(event:Event):void {
            if ( _IsInitComplete ) {
                _timer.stop();
                _timer.removeEventListener(TimerEvent.TIMER,timerHandler);

		dispatchEvent(new Event(Event.COMPLETE));
            }
            else {
            	loadingText.text = Math.ceil(_fractionLoaded*100).toString();
            	loadingText.x = stage.fullScreenWidth / 2 - loadingText.width / 2;

            	// Tutaj następuje przerysowanie pasków otaczających label, kod prezentuje na końcu wpisu
                draw();
            }
        }</pre>
<p>Preloader dostarcza nam 4 zdarzenia, które wywołuje w odpowiednim czasie. Są to:</p>
<ol>
<li>progressHandler &#8211; wywoływany za każdym razem, gdy przeglądarka ściągnie kolejną część aplikacji</li>
<li>completeHandler &#8211; wywoływany, gdy aplikacja skończy się ściągać</li>
<li>initProgressHandler &#8211; wywoływana podczas postępu inicjalizacji</li>
<li>initCompleteHandler &#8211; wywoływana, gdy inicjalizacja się zakończy</li>
</ol>
<p>Naszym zadaniem jest implementacja metod <em>progressHandler </em>oraz <em>initCompleteHandler. </em>W<em> progressHandler </em>updatujemy pola odpowiedzialne za procent wczytania aplikacji:</p>
<pre class="brush:js">        private var _bytesLoaded 		: uint = 0;
        private var _bytesExpected 		: uint = 1;

       private function progressHandler(event:ProgressEvent):void {
            _bytesLoaded = event.bytesLoaded;
            _bytesExpected = event.bytesTotal;
            _fractionLoaded = Number(_bytesLoaded) / Number(_bytesExpected);
        }</pre>
<p>W metodzie <em>initCompleteHandler</em> ustawiamy pole odpowiedzialne za zakończenie działania preloadera na <em>true</em>. Dzięki temu nasz Timer, może zakończyć działanie. Robi to poprzez wywołanie zdarzenia Event.COMPLETE, tak jak to widać w metodzie <em>timerHandler</em>.</p>
<pre class="brush:js">        private function initCompleteHandler(event:Event):void {
        	_IsInitComplete = true;
        }</pre>
<p>Teraz zaprezentuje metody, które używam to obrysowania labela paskami, które tworzą koło. Niestety nie można we Flexie rysować częściowych kół (coś a&#8217;la pizza bez kawałka). Mój sposób polega na tym, żeby rysować od trójkąty z jednym punktem wspólnym w środku, zaś kolejnymi parami punktów dookoła labela.</p>
<pre class="brush:js">        private function draw():void {
            graphics.clear();

            fillAct(graphics, stage.fullScreenWidth / 2, loadingText.y + loadingText.height/2, _fractionLoaded*360 , 25);
            graphics.beginFill( 0xffffff , 1);
	    graphics.drawCircle(stage.fullScreenWidth / 2, loadingText.y + loadingText.height/2, 20);
            graphics.endFill();
        }

        private function fillAct(g:Graphics, x:Number, y:Number, angle:Number, radius:Number):void {
        	var trCounts:Number = Math.ceil(angle / 5);
        	var radFrom:Number, radTo:Number;

        	g.beginFill(0x000000);
        	for (var i:int = 0; i &lt; trCounts; i+=2) {
        		radFrom = -i*5*Math.PI / 180;
        		radTo = (-i*5 + 5)*Math.PI / 180;

        		g.moveTo(x,y);
        		g.lineTo(x + Math.sin(radFrom)*radius, y + Math.cos(radFrom)*radius);
        		g.lineTo(x + Math.sin(radTo)*radius, y + Math.cos(radTo)*radius);
        		g.lineTo(x,y);
        	}
        	g.endFill();
        }</pre>
<p>Ten kod po złączeniu daje efekt zaprezentowany w przykładzie :) Mam nadzieje, że wszystko jest zrozumiałe. W razie pytań, proszę komentować :)</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.flexmaniak.pl/actionscript/custom-preloader/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

