Статьи

Создание гаджета поиска и воспроизведения YouTube с помощью PureMVC

После моих уроков по PureMVC и API проигрывателя YouTube я подумал, что будет хорошей идеей показать вам, как использовать API GData YouTube для поиска и воспроизведения видео. Итак, я создал небольшой учебник, который объединяет ваши новые навыки PureMVC и YouTube Player в приятный и простой гаджет поиска и воспроизведения.




Это учебник для продвинутых и продвинутых сценариев Actionscripters, и он будет полезен, если вы сначала прочитаете мои учебники по API PureMVC и YouTube Player .

Вы можете быть удивлены, почему я решил использовать PureMVC. Ну, я думаю, что это здорово! И это отличный инструмент, который позволяет вам создать что-то маленькое, а затем превратить его в большое приложение — все дело в масштабируемости. Поэтому, когда мы создаем это приложение, стоит отметить, что его можно использовать в качестве гаджета для включения в несколько мест, таких как iGoogle, блоги и даже объявления гаджетов .

Запустите вашу любимую IDE, будь то Flex Builder , FDT , FlashDevelop или TextMate, и создайте новый проект ActionScript. Мы также собираемся создать SWC, так что это удобно, если у вас есть копия Flash ( вы можете скачать след с веб-сайта Adobe ).

Кроме того, мы собираемся использовать класс GreenSock TweenLite и не забывать кодовую базу PureMVC .

Примечание. В первые несколько шагов мы собираемся настроить каркас для PureMVC. Объяснение первых шагов доступно в моем руководстве по PureMVC .

Как и в любом приложении PureMVC, нам нужно настроить наше базовое приложение. Я собираюсь начать с создания простого фона для приложения и запуска команды запуска внутри фасада, поэтому создайте новый файл с именем «App.as» в «src /»:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package
{
    import com.flashtuts.ApplicationFacade;
 
    import flash.display.GradientType;
    import flash.display.Sprite;
    import flash.geom.Matrix;
    import flash.text.Font;
 
    [SWF( width=’600′, height=’400′, frameRate=’30’, backgroundColor=’#000000′ )]
 
    public class App extends Sprite
    {
        [Embed( systemFont=’Arial’, fontName=’Arial’, mimeType=’application/x-font’ )]
        private var arialFont:Class;
 
        public function App()
        {
            init();
        }
 
        private function init():void
        {
            var mat:Matrix = new Matrix();
            var bg:Sprite = new Sprite();
 
            mat.createGradientBox( stage.stageWidth, stage.stageHeight, Math.PI * .5 );
 
            bg.graphics.beginGradientFill( GradientType.LINEAR, [ 0x333333, 0x000000 ], [ 1, 1 ], [ 0, 255 ], mat );
            bg.graphics.drawRect( 0, 0, stage.stageWidth, stage.stageHeight );
            bg.graphics.endFill();
 
            addChild( bg );
 
            Font.registerFont( arialFont );
 
            ApplicationFacade.getInstance().startup( this );
        }
    }
}

Теперь мы просто создаем фасад, ничего особенного, как фасад, который мы создали в учебном пособии по PureMVC , поэтому создайте новый файл с именем «ApplicationFacade.as» внутри «src / com / flashtuts /»:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.flashtuts
{
    import com.flashtuts.controller.StartupCommand;
 
    import org.puremvc.as3.interfaces.IFacade;
    import org.puremvc.as3.patterns.facade.Facade;
    import org.puremvc.as3.patterns.observer.Notification;
 
    public class ApplicationFacade extends Facade implements IFacade
    {
        public static const NAME:String = ‘ApplicationFacade’;
 
        public static const STARTUP:String = NAME + ‘StartUp’;
 
        public static function getInstance():ApplicationFacade
        {
            return (instance ? instance : new ApplicationFacade()) as ApplicationFacade;
        }
 
        override protected function initializeController():void
        {
            super.initializeController();
 
            registerCommand( STARTUP, StartupCommand );
        }
 
        public function startup(stage:Object):void
        {
            sendNotification( STARTUP, stage );
        }
 
        override public function sendNotification(notificationName:String, body:Object=null, type:String=null):void
        {
            trace( ‘Sent ‘ + notificationName );
 
            notifyObservers( new Notification( notificationName, body, type ) );
        }
    }
}

Теперь мы создадим команду запуска и убедимся, что мы зарегистрировали наш прокси и посредник приложения. Создайте файл с именем «StartupCommand.as» в «src / com / flashtuts / controller /»:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
package com.flashtuts.controller
{
    import com.flashtuts.model.DataProxy;
    import com.flashtuts.view.ApplicationMediator;
 
    import org.puremvc.as3.interfaces.ICommand;
    import org.puremvc.as3.interfaces.INotification;
    import org.puremvc.as3.patterns.command.SimpleCommand;
 
    public class StartupCommand extends SimpleCommand implements ICommand
    {
        override public function execute(notification:INotification):void
        {
            facade.registerProxy( new DataProxy() );
 
            facade.registerMediator( new ApplicationMediator( notification.getBody() as App ) );
        }
    }
}

Теперь нам нужно настроить наш прокси, поэтому давайте создадим файл с именем «DataProxy.as» в «src / com / flashtuts / model /»:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.flashtuts.model
{
    import com.flashtuts.model.vo.DataVO;
 
    import org.puremvc.as3.interfaces.IProxy;
    import org.puremvc.as3.patterns.proxy.Proxy;
 
    public class DataProxy extends Proxy implements IProxy
    {
        public static const NAME:String = ‘DataProxy’;
 
        public function DataProxy()
        {
            super( NAME, new DataVO() );
        } new Proxy
 
        public function get vo():DataVO
        {
            return data as DataVO;
        }
    }
}

Мы вернемся к прокси позже в этом уроке, так как будем использовать его для загрузки данных из GData и сохранения их в VO.

Мы собираемся использовать VO для хранения данных из нашего запроса GData, так что если пользователь ищет ключевое слово более одного раза, мы просто загрузим данные из VO, а не создадим другой запрос к API GData. Создайте файл с именем «DataVO.as» в «src / com / flashtuts / model / vo /»:

01
02
03
04
05
06
07
08
09
10
package com.flashtuts.model.vo
{
    import flash.utils.Dictionary;
 
    public class DataVO
    {
        public var gdataURL:String = ‘http://gdata.youtube.com/feeds/api/videos?orderby=published&max-results=15&v=2&q=’;
        public var queryResults:Dictionary = new Dictionary();
    }
}

Быстро прочитав документацию по API GData, вы увидите, что переменная «gdataURL» показывает, что мы собираемся получить 15 результатов, и мы оставили открытый URL-адрес, чтобы можно было поместить строку запроса в конце URL запроса.

Заключительная часть нашего скелета PureMVC — это наш посредник в приложениях. Мы создадим его, а затем получим его для регистрации нашего первого представления и посредника, «ProgressView» и «ProgressViewMediator», поэтому создайте файл с именем «ProgressViewMediator.as» в «src / com / flashtuts / view /»:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.flashtuts.view
{
    import org.puremvc.as3.interfaces.IMediator;
    import org.puremvc.as3.interfaces.INotification;
    import org.puremvc.as3.patterns.mediator.Mediator;
 
    public class ApplicationMediator extends Mediator implements IMediator
    {
        public static const NAME:String = ‘ApplicationMediator’;
 
        public function ApplicationMediator(viewComponent:Object=null)
        {
            super( NAME, viewComponent );
        }
 
        override public function onRegister():void
        {
             
        }
 
        override public function listNotificationInterests():Array
        {
            return [
            ];
        }
 
        override public function handleNotification(notification:INotification):void
        {
            var name:String = notification.getName();
            var body:Object = notification.getBody();
 
            switch ( name )
            {
                 
            }
        }
    }
}

Мы просто начнем с представления прогресса, аналогичного тому, которое мы сделали в учебном пособии по PureMVC , поэтому создайте файл «ProgressView.as» в «src / com / flashtuts / view / component /»:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.flashtuts.view.component
{
    import flash.display.Sprite;
 
    import gs.TweenLite;
 
    public class ProgressView extends Sprite
    {
        public static const NAME:String = ‘ProgressView’;
 
        public static const SHOW:String = NAME + ‘Show’;
        public static const HIDE:String = NAME + ‘Hide’;
 
        private var asset:LoaderAsset;
 
        public function ProgressView()
        {
            init();
        }
 
        private function init():void
        {
            asset = new LoaderAsset();
 
            asset.stop();
            asset.x = 275;
            asset.y = 175;
 
            addChild( asset );
        }
 
        public function show():void
        {
            asset.play();
 
            TweenLite.to( this, .5, { autoAlpha: 1 } );
        }
 
        public function hide():void
        {
            asset.stop();
 
            TweenLite.to( this, .5, { autoAlpha: 0 } );
        }
    }
}

Вы заметите, что мы используем новый класс под названием «LoaderAsset». На самом деле это мувиклип, который мы создадим во Flash IDE, а затем используем в нашем представлении прогресса, а не просто показываем процент.

Запустите Flash IDE (если у вас нет Flash IDE, вы можете загрузить пробную версию с веб-сайта Adobe ) и создайте новый файл AS3:

Прежде чем продолжить, мы должны убедиться, что Flash знает, что мы хотим нацелить на Flash Player 9 и что мы экспортируем SWC, поэтому выберите «Flash Player 9» в раскрывающемся списке вверху и установите флажок «Экспорт» SWC »под заголовком« Настройки SWF »:

Теперь мы создадим простой загрузчик. Я решил пойти на спиннинг, но это зависит от вас, что вы делаете. Создайте круг и пробейте в нем дыру:

После того, как вы сделали отверстие в своем круге, примените радиальный градиент, переместите его вправо от круга. Затем скопируйте половину круга, вставьте его поверх текущего круга и примените к нему сплошную заливку. Выполнено. Теперь, следующая вещь — заставить его вращаться, поэтому давайте создадим анимацию движения:

У меня есть твоя анимация, бегущая на 15 кадров, ты можешь делать свою быструю, такую ​​же или медленную. Теперь мы просто установили его на один оборот:

Последнее, что нужно сделать, это обернуть все это в видеоклип. Как только вы это сделаете, откройте окно свойств для этого мувиклипа и установите его для экспорта для Actionscript:

Как вы можете видеть, я назвал его «LoaderAsset», это имя связи будет именем класса, которое вы будете использовать в своем представлении, поэтому вернемся к нашему «ProgressView». Убедитесь, что вы добавили свой ресурс так же, как я сделал в классе:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.flashtuts.view.component
{
    import flash.display.Sprite;
 
    import gs.TweenLite;
 
    public class ProgressView extends Sprite
    {
        public static const NAME:String = ‘ProgressView’;
 
        public static const SHOW:String = NAME + ‘Show’;
        public static const HIDE:String = NAME + ‘Hide’;
 
        private var asset:LoaderAsset;
 
        public function ProgressView()
        {
            init();
        }
 
        private function init():void
        {
            asset = new LoaderAsset();
 
            asset.stop();
            asset.x = 275;
            asset.y = 175;
 
            addChild( asset );
        }
 
        public function show():void
        {
            asset.play();
 
            TweenLite.to( this, .5, { autoAlpha: 1 } );
        }
 
        public function hide():void
        {
            asset.stop();
 
            TweenLite.to( this, .5, { autoAlpha: 0 } );
        }
    }
}

Наш посредник представления прогресса будет аналогичен тому, который мы создали в учебном пособии по PureMVC, за исключением того, что обновления нет, поскольку у нас просто вращающееся колесо, а не знак процента. Создайте файл «ProgressViewMediator.as» в «src / com / flashtuts / view /»:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package com.flashtuts.view
{
    import com.flashtuts.view.component.ProgressView;
 
    import org.puremvc.as3.interfaces.IMediator;
    import org.puremvc.as3.interfaces.INotification;
    import org.puremvc.as3.patterns.mediator.Mediator;
 
    public class ProgressViewMediator extends Mediator implements IMediator
    {
        public static const NAME:String = ‘ProgressViewMediator’;
 
        private var progressView:ProgressView;
 
        public function ProgressViewMediator(viewComponent:Object=null)
        {
            super( NAME, viewComponent );
        }
 
        override public function onRegister():void
        {
            progressView = new ProgressView();
 
            progressView.hide();
 
            viewComponent.addChild( progressView );
        }
 
        override public function listNotificationInterests():Array
        {
            return [
                ProgressView.SHOW,
                ProgressView.HIDE
            ];
        }
 
        override public function handleNotification(notification:INotification):void
        {
            var name:String = notification.getName();
            var body:Object = notification.getBody();
 
            switch ( name )
            {
                case ProgressView.SHOW:
                progressView.show();
 
                break;
 
                case ProgressView.HIDE:
                progressView.hide();
 
                break;
            }
        }
    }
}

Вы можете использовать любой желаемый загрузчик, но есть проблема с GData YouTube. Вы видите, что когда Flash Player выполняет вызов, большинство серверов отправляют загрузчику содержимое с длиной содержимого, что позволяет Flash Player узнать, сколько байт он собирается загрузить, и позволяет нам вычислить процент. Однако YouTube GData, похоже, не передает эту длину контента, и всякий раз, когда вы пытаетесь вычислить процент, Flash Player обнаруживает, что разделяет «bytesLoaded» на ноль. Позор.

Следующее, что нам нужно сделать, это создать наш вид поиска Он будет содержать окно поиска, в котором пользователь будет вводить свой запрос, а затем кнопку, которую он нажимает, чтобы выполнить запрос. Кроме того, мы будем использовать прослушиватель событий в окне поиска, чтобы, если бы пользователь нажал «enter», запрос все равно был бы выполнен. Создайте файл с именем «SearchView.as» в «src / com / flashtuts / view / component /»:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
+015
016
+017
018
019
020
021
022
023
024
025
026
027
028
029
+030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
+055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package com.flashtuts.view.component
{
    import flash.display.Sprite;
    import flash.events.DataEvent;
    import flash.events.FocusEvent;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFieldType;
    import flash.text.TextFormat;
    import flash.ui.Keyboard;
 
    import mx.utils.StringUtil;
 
    public class SearchView extends Sprite
    {
        public static const NAME:String = ‘SearchView’;
 
        public static const SHOW:String = NAME + ‘Show’;
        public static const HIDE:String = NAME + ‘Hide’;
        public static const SEARCH_RUN:String = NAME + ‘SearchRun’;
        public static const SEARCH_RESULTS:String = NAME + ‘SearchResults’;
 
        public static const SEARCH_FIELD_STRING:String = ‘Keywords…’;
 
        private var searchField:TextField;
 
        public function SearchView()
        {
            init();
        }
 
        private function init():void
        {
            var textFormat:TextFormat = new TextFormat();
            var boxBg:Sprite = new Sprite();
            var boxCopy:TextField = new TextField();
            var boxButton:Sprite = new ButtonAsset();
 
            textFormat.color = 0x000000;
            textFormat.font = ‘Arial’;
            textFormat.size = 10;
 
            boxBg.graphics.beginFill( 0xFFFFFF );
            boxBg.graphics.drawRoundRectComplex( 0, 0, 300, 35, 0, 0, 5, 5 );
            boxBg.graphics.endFill();
            boxBg.x = 150;
 
            addChild( boxBg );
 
            boxCopy.autoSize = TextFieldAutoSize.LEFT;
            boxCopy.defaultTextFormat = textFormat;
            boxCopy.embedFonts = true;
            boxCopy.text = ‘Search for:’;
            boxCopy.x = 10;
            boxCopy.y = ( boxBg.height / 2 ) — ( boxCopy.height / 2 );
 
            boxBg.addChild( boxCopy );
 
            searchField = new TextField();
 
            searchField.border = true;
            searchField.borderColor = 0x666666;
            searchField.defaultTextFormat = textFormat;
            searchField.embedFonts = true;
            searchField.multiline = false;
            searchField.text = SEARCH_FIELD_STRING;
            searchField.type = TextFieldType.INPUT;
            searchField.width = 185;
            searchField.height = 16;
            searchField.x = boxCopy.x + boxCopy.width + 10;
            searchField.y = ( boxBg.height / 2 ) — ( searchField.height / 2 );
 
            searchField.addEventListener( FocusEvent.FOCUS_IN, handleSearchFieldFocusIn );
            searchField.addEventListener( FocusEvent.FOCUS_OUT, handleSearchFieldFocusOut );
            searchField.addEventListener( KeyboardEvent.KEY_UP, handleSearchFieldKeyUp );
 
            boxBg.addChild( searchField );
 
            boxButton.buttonMode = true;
            boxButton.x = boxCopy.x + boxCopy.width + searchField.width + 20;
            boxButton.y = ( boxBg.height / 2 ) — ( boxButton.height / 2 );
 
            boxButton.addEventListener( MouseEvent.CLICK, searchRun );
 
            boxBg.addChild( boxButton );
        }
 
        private function handleSearchFieldFocusIn(e:FocusEvent):void
        {
            if ( searchField.text === SEARCH_FIELD_STRING )
            {
                searchField.text = »;
            }
        }
 
        private function handleSearchFieldFocusOut(e:FocusEvent):void
        {
            if ( StringUtil.trim( searchField.text ) == » )
            {
                searchField.text = SEARCH_FIELD_STRING;
            }
        }
 
        private function handleSearchFieldKeyUp(e:KeyboardEvent):void
        {
            if ( e.keyCode === Keyboard.ENTER )
            {
                searchRun();
            }
        }
 
        private function searchRun(e:*=null):void
        {
            var query:String = StringUtil.trim( searchField.text );
 
            if ( query != » && query != SEARCH_FIELD_STRING )
            {
                dispatchEvent( new DataEvent( SEARCH_RUN, true, false, query ) );
            }
        }
    }
}

Этот код не должен быть чем-то новым для ActionScripter, но вот быстрый прогон: сначала мы устанавливаем текстовый формат, затем создаем фоновое поле (я использую Sprite.drawRoundRectComplex () для рисования окна), затем я настраиваю создайте текстовое поле ввода, а затем импортируйте актив из SWC для кнопки поиска.

Как я уже упоминал ранее, я добавил прослушиватель событий в поле ввода текста и кнопку отправки. Это означает, что пользователь может нажать клавишу ввода или нажать кнопку отправки, чтобы выполнить запрос. Функция handleSearchFieldKeyUp () проверяет, была ли нажата клавиша ввода, если она была нажата, затем выполняет поиск. Это также хорошая практика для вопросов юзабилити, поскольку люди часто нажимают клавишу ввода, а не нажимают кнопку.

Посредника поискового представления там не будет слишком много, поскольку он не прослушивает какие-либо события, скорее он отправляет их на фасад. Начните с создания файла с именем «SearchViewMediator.as» внутри «src / com / flashtuts / view /»:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.flashtuts.view
{
    import com.flashtuts.view.component.SearchView;
 
    import flash.events.DataEvent;
 
    import org.puremvc.as3.interfaces.IMediator;
    import org.puremvc.as3.patterns.mediator.Mediator;
 
    public class SearchViewMediator extends Mediator implements IMediator
    {
        public static const NAME:String = ‘SearchViewMediator’;
 
        private var searchView:SearchView;
 
        public function SearchViewMediator(viewComponent:Object=null)
        {
            super( NAME, viewComponent );
        }
 
        override public function onRegister():void
        {
            searchView = new SearchView();
 
            searchView.addEventListener( SearchView.SEARCH_RUN, sendEvent );
 
            viewComponent.addChild( searchView );
        }
 
        private function sendEvent(e:DataEvent):void
        {
            sendNotification( SearchView.SEARCH_RUN, { query: e.data } );
        }
    }
}

Если вы посмотрите на представление, то заметите, что оно отправит «DataEvent» посреднику. В рамках нашего посредника мы слушаем это и затем отправляем уведомление на ваш фасад. Это уведомление будет получено командой, которая будет взаимодействовать с прокси и затем отправлять событие с результатами.

Мы достигли стадии, когда наше представление будет отправлять наш запрос на фасад, поэтому теперь нам нужно создать команду, чтобы передать этот запрос нашему прокси, а затем обновить код нашего прокси. Затем он выполнит запрос, сохранит его в VO, передаст его обратно посреднику, а затем представлению.

Мы собираемся начать с обновления фасада, чтобы он передавал уведомление «SearchView.SEARCH_RUN» нашей команде данных. Откройте «ApplicationFacade.as» и просто добавьте еще одну «registerCommand» в функцию «initializeController ()» фасада:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.flashtuts
{
    import com.flashtuts.controller.DataCommand;
    import com.flashtuts.controller.StartupCommand;
    import com.flashtuts.view.component.SearchView;
 
    import org.puremvc.as3.interfaces.IFacade;
    import org.puremvc.as3.patterns.facade.Facade;
    import org.puremvc.as3.patterns.observer.Notification;
 
    public class ApplicationFacade extends Facade implements IFacade
    {
        public static const NAME:String = ‘ApplicationFacade’;
 
        public static const STARTUP:String = NAME + ‘StartUp’;
 
        public static function getInstance():ApplicationFacade
        {
            return (instance ? instance : new ApplicationFacade()) as ApplicationFacade;
        }
 
        override protected function initializeController():void
        {
            super.initializeController();
 
            registerCommand( STARTUP, StartupCommand );
 
            registerCommand( SearchView.SEARCH_RUN, DataCommand );
        }
 
        public function startup(stage:Object):void
        {
            sendNotification( STARTUP, stage );
        }
 
        override public function sendNotification(notificationName:String, body:Object=null, type:String=null):void
        {
            trace( ‘Sent ‘ + notificationName );
 
            notifyObservers( new Notification( notificationName, body, type ) );
        }
    }
}

Теперь нам нужно создать файл «DataCommand.as» в «src / com / flashtuts / controller /»:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.flashtuts.controller
{
    import com.flashtuts.model.DataProxy;
    import com.flashtuts.view.component.SearchView;
 
    import org.puremvc.as3.interfaces.ICommand;
    import org.puremvc.as3.interfaces.INotification;
    import org.puremvc.as3.patterns.command.SimpleCommand;
 
    public class DataCommand extends SimpleCommand implements ICommand
    {
        override public function execute(notification:INotification):void
        {
            var name:String = notification.getName();
            var body:Object = notification.getBody();
 
            switch ( name )
            {
                case SearchView.SEARCH_RUN:
                proxy.searchRun( body.query );
 
                break;
            }
        }
 
        private function get proxy():DataProxy
        {
            return facade.retrieveProxy( DataProxy.NAME ) as DataProxy;
        }
    }
}

Это довольно простой контроллер, он прослушивает одно уведомление, а затем просто передает его прокси. Опять же, мы ссылаемся на прокси с помощью функции get , это означает, что мы используем экземпляр фасада, а не повторно объявляем прокси.

Теперь, когда наше представление накапливает событие на фасаде, а фасад передает его нашей команде данных, нам нужен прокси-сервер для грязной работы, поэтому давайте загрузим немного XML.

Если вы раньше не работали с GData, стоит отметить, что XML, который он передает обратно, находится в формате Atom, и в нем есть много пространств имен . В AS2 использование пространств имен было чем-то вроде взлома, как и остальной язык, но теперь в AS3 есть два способа:

  1. Правильный путь
    Это правильный путь, но это неприятность, так как вам нужно объявить каждое пространство имен в AS3 перед загрузкой в ​​XML, например, так:
    1
    2
    3
    var rss:Namespace = new Namespace(«http://purl.org/rss/1.0/»);
    var rdf:Namespace = new Namespace(«http://www.w3.org/1999/02/22-rdf-syntax-ns#»);
    var dc:Namespace = new Namespace(«http://purl.org/dc/elements/1.1/»);

    Только тогда вы можете получить доступ к переменным XML следующим образом:

    1
    var item:String = items[i].dc::date;

    Итак, вы видите, что вы поместили объявленное пространство имен и две двоеточия (this 🙂 перед именем тега / атрибута. Это может показаться болезненным — и это так, но вы можете узнать больше о LiveDocs от Adobe .

  2. Легкий способ
    Этот способ намного проще (и, я полагаю, ленивее), но он выполняет свою работу и не является беспорядком или хакерством. Пространство имен — это просто метод для привязки тегов (или атрибутов) к URL-ссылке, например, GData ссылается на собственные схемы OpenSearch, YouTube и Google и многое другое. Самый простой способ — вместо того, чтобы объявлять пространства имен и добавлять к ним имена тегов / атрибутов, вы просто добавляете звездочку (это *) следующим образом:
    1
    var item:String = items[i].*::date;

    Легко!

Итак, теперь мы понимаем, как обрабатывать возвращаемый XML, давайте перейдем к завершению прокси. Запустите «DataProxy.as» в «src / com / flashtuts / model /» и вот код для него:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package com.flashtuts.model
{
    import com.flashtuts.model.vo.DataVO;
    import com.flashtuts.view.component.ProgressView;
    import com.flashtuts.view.component.SearchView;
 
    import flash.events.Event;
    import flash.events.ProgressEvent;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.utils.Dictionary;
 
    import org.puremvc.as3.interfaces.IProxy;
    import org.puremvc.as3.patterns.proxy.Proxy;
 
    public class DataProxy extends Proxy implements IProxy
    {
        public static const NAME:String = ‘DataProxy’;
 
        private var queryDic:Dictionary = new Dictionary();
 
        public function DataProxy()
        {
            super( NAME, new DataVO() );
        }
 
        public function searchRun(query:String):void
        {
            if ( vo.queryResults[ query ] )
            {
                dataReady( query );
            }
            else
            {
                dataLoad( query );
            }
        }
 
        private function dataLoad(query:String):void
        {
            var request:URLRequest = new URLRequest( vo.gdataURL + query );
            var loader:URLLoader = new URLLoader();
 
            sendNotification( ProgressView.SHOW );
 
            queryDic[ loader ] = query;
 
            loader.addEventListener( Event.COMPLETE, handleSearchComplete );
 
            loader.load( request );
        }
 
        private function handleSearchComplete(e:Event):void
        {
            var data:XML = new XML( e.target.data );
 
            vo.queryResults[ queryDic[ e.target ] ] = data..*::entry;
 
            dataReady( queryDic[ e.target ] );
        }
 
        private function dataReady(query:String):void
        {
            sendNotification( SearchView.SEARCH_RESULTS, { entries: vo.queryResults[ query ] } );
 
            sendNotification( ProgressView.HIDE );
        }
 
        public function get vo():DataVO
        {
            return data as DataVO;
        }
    }
}

Мы начнем с создания общедоступной функции, которая будет вызывать нашу команду data «searchRun ()». Как видите, он принимает один параметр, строку запроса:

01
02
03
04
05
06
07
08
09
10
11
public function searchRun(query:String):void
{
    if ( vo.queryResults[ query ] )
    {
        dataReady( query );
    }
    else
    {
        dataLoad( query );
    }
}

Теперь чтобы приложение работало быстрее. Я использую принцип, согласно которому после выполнения запроса данные сохраняются в VO, и нет необходимости повторять этот запрос. Таким образом, используя класс словаря AS3, мы можем проверить, есть ли результаты уже в ВО. Если это не так, нам нужно их получить, иначе отправьте их нашему посреднику. Мы перейдем к функции dataReady () чуть ниже:

Если запрос еще не был выполнен, нам нужно загрузить XML:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
private function dataLoad(query:String):void
{
    var request:URLRequest = new URLRequest( vo.gdataURL + query );
    var loader:URLLoader = new URLLoader();
 
    sendNotification( ProgressView.SHOW );
 
    queryDic[ loader ] = query;
 
    loader.addEventListener( Event.COMPLETE, handleSearchComplete );
 
    loader.load( request );
}
 
private function handleSearchComplete(e:Event):void
{
    var data:XML = new XML( e.target.data );
 
    vo.queryResults[ queryDic[ e.target ] ] = data..*::entry;
 
    dataReady( queryDic[ e.target ] );
}

Вы увидите, что мы добавляем запрос к строке ‘gdataURL’, хранящейся в нашем VO. Затем мы ссылаемся на строку запроса, используя словарь прокси, чтобы, когда данные были готовы, мы могли сохранить их в VO под этим запросом и не нуждались в их повторной загрузке. Затем мы добавляем прослушиватели событий и делаем вызов. Получив данные обратно, мы получаем запрос из словаря, сохраняем его в VO и затем запускаем функцию «dataReady ()»:

1
2
3
4
5
6
private function dataReady(query:String):void
{
    sendNotification( SearchView.SEARCH_RESULTS, { entries: vo.queryResults[ query ] } );
 
    sendNotification( ProgressView.HIDE );
}

Эта функция просто получает записи и отправляет уведомление обратно на фасад. Теперь мы можем показывать наши видео.

После того, как у нас есть записи, мы можем легко загрузить эскизы для этих записей и отобразить их в виде сетки. Начнем с создания файла с именем «ResultsView.as» внутри «src / com / flashtuts / component /»:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
+015
016
+017
018
019
020
021
022
023
024
025
026
027
028
029
+030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
+055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
package com.flashtuts.view.component
{
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.events.DataEvent;
    import flash.events.MouseEvent;
    import flash.net.URLRequest;
    import flash.utils.Dictionary;
 
    public class ResultsView extends Sprite
    {
        public static const NAME:String = ‘ResultsView’;
 
        public static const SHOW:String = NAME + ‘Show’;
        public static const HIDE:String = NAME + ‘Hide’;
        public static const CLICKED:String = NAME + ‘Clicked’;
 
        private var idsDic:Dictionary = new Dictionary();
        private var thumbnailHeight:Number = 90;
        private var thumbnailSpacing:Number = 10;
        private var thumbnailWidth:Number = 100;
 
        public function buildThumbnails(entries:Object):void
        {
            var ix:Number = 0;
            var iy:Number = 0;
            var thumbnails:Sprite = new Sprite();
            var thumbnail:Sprite;
 
            if ( numChildren > 0 )
            {
                for ( var i:Number = 0; i < numChildren; i++ )
                {
                    removeChildAt( i );
                }
 
                buildThumbnails( entries );
            }
            else
            {
                for each ( var entry:XML in entries )
                {
                    thumbnail = createThumbnail( entry );
 
                    thumbnail.x = ( thumbnailWidth + thumbnailSpacing ) * ix;
                    thumbnail.y = ( thumbnailHeight + thumbnailSpacing ) * iy;
 
                    if ( ix > 3 )
                    {
                        ix = 0;
                        iy++;
                    }
                    else
                    {
                        ix++;
                    }
 
                    thumbnails.addChild( thumbnail );
                }
 
                thumbnails.x = 25;
                thumbnails.y = 70;
 
                addChild( thumbnails );
            }
        }
 
        private function createThumbnail(entry:XML):Sprite
        {
            var thumbnail:Sprite = new Sprite();
            var mask:Sprite = new Sprite();
            var request:URLRequest = new URLRequest( entry..*::thumbnail[ 0 ][email protected]() );
            var loader:Loader = new Loader();
 
            idsDic[ thumbnail ] = entry..*::videoid.toString();
 
            mask.graphics.beginFill( 0x000000 );
            mask.graphics.drawRoundRect( 0, 0, thumbnailWidth, thumbnailHeight, 5, 5 );
            mask.graphics.endFill();
 
            thumbnail.addChild( mask );
 
            loader.load( request );
 
            thumbnail.addChild( loader );
 
            loader.mask = mask;
 
            thumbnail.buttonMode = true;
            thumbnail.mouseChildren = false;
 
            thumbnail.addEventListener( MouseEvent.CLICK, handleThumbnailClicked );
 
            return thumbnail;
        }
 
        private function handleThumbnailClicked(e:MouseEvent):void
        {
            dispatchEvent( new DataEvent( CLICKED, true, false, idsDic[ e.target ] ) );
        }
    }
}

Это просто класс, который просто берет идентификаторы видео YouTube, а затем загружает соответствующий эскиз. Прежде всего, мы начинаем с удаления всех дочерних элементов представления, и когда это делается, мы выполняем цикл, который затем загружает миниатюру, маскирует ее (поэтому у нас есть хорошие закругленные углы) и добавляет прослушиватель событий в спрайт. Вы заметите, что я снова использую словарь, который называется «idsDic». Это будет просто хранить ссылку на спрайт, добавляемый на сцену, чтобы при нажатии на него мы знали соответствующий идентификатор видео YouTube для загрузки.

Наконец, вы увидите, что класс отправляет «DataEvent», содержащее идентификатор видео, обратно его посреднику.

У этого посредника будет две простые работы:

  1. Чтобы (повторно) построить эскизы, когда запрос был выполнен
  2. Чтобы передать идентификатор видео на наш плеер YouTube

Итак, начнем с создания файла «ResultsViewMediator.as» в «src / com / flashtuts / view /»:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.flashtuts.view
{
    import com.flashtuts.view.component.PlayerView;
    import com.flashtuts.view.component.ResultsView;
    import com.flashtuts.view.component.SearchView;
 
    import flash.events.DataEvent;
 
    import org.puremvc.as3.interfaces.IMediator;
    import org.puremvc.as3.interfaces.INotification;
    import org.puremvc.as3.patterns.mediator.Mediator;
 
    public class ResultsViewMediator extends Mediator implements IMediator
    {
        public static const NAME:String = ‘ResultsViewMediator’;
 
        private var resultsView:ResultsView;
 
        public function ResultsViewMediator(viewComponent:Object=null)
        {
            super( NAME, viewComponent );
        }
 
        override public function onRegister():void
        {
            resultsView = new ResultsView();
 
            resultsView.addEventListener( ResultsView.CLICKED, sendEvent );
 
            viewComponent.addChild( resultsView );
        }
 
        override public function listNotificationInterests():Array
        {
            return [
                SearchView.SEARCH_RESULTS
            ];
        }
 
        override public function handleNotification(notification:INotification):void
        {
            var name:String = notification.getName();
            var body:Object = notification.getBody();
 
            switch ( name )
            {
                case SearchView.SEARCH_RESULTS:
                resultsView.buildThumbnails( body.entries );
 
                break;
            }
        }
 
        private function sendEvent(e:DataEvent):void
        {
            sendNotification( PlayerView.PLAY, { videoId: e.data } );
        }
    }
}

Как я уже говорил, этот посредник прослушивает SearchView.SEARCH_RESULTS (отправляемый прокси-сервером) и отправляет PlayerView.PLAY после создания эскиза. Теперь мы можем приступить к созданию представления проигрывателя, в котором будет размещен проигрыватель YouTube.

Прежде чем вы начнете с этим, вы должны прочитать руководство по API YouTube Player, которое я написал, поскольку мы будем использовать его здесь. В этом уроке мы создали набор классов и оболочку игрока. Теперь скопируйте этот проигрыватель и вставьте его в «src / assets / swf /». Что касается наших классов, я поместил их в простой каталог многократного использования под названием «src / com / flashtuts / lib /», поэтому у меня есть класс «YouTubePlayer.as» в «src / com / flashtuts / lib / display» / «и» YouTubePlayerEvent.as «в» src / com / flashtuts / lib / events / «. Это будет означать, что вы можете легко использовать эти классы снова и снова.

Когда вы будете довольны расположением классов вашего плеера YouTube, мы начнем с представления плеера, поэтому создайте новый файл с именем «PlayerView.as» внутри «src / com / flashtuts / view / component /»:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package com.flashtuts.view.component
{
    import com.flashtuts.lib.display.YouTubePlayer;
 
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.filters.GlowFilter;
 
    public class PlayerView extends Sprite
    {
        public static const NAME:String = ‘PlayerView’;
 
        public static const PLAY:String = NAME + ‘Play’;
        public static const CLOSE:String = NAME + ‘Close’;
 
        private var player:YouTubePlayer;
 
        public function PlayerView()
        {
            init();
        }
 
        private function init():void
        {
            var bg:Sprite = new Sprite();
            var closeButton:CloseButtonAsset = new CloseButtonAsset();
 
            bg.graphics.beginFill( 0x000000, .8 );
            bg.graphics.drawRect( 0, 0, 600, 400 );
            bg.graphics.endFill();
 
            addChild( bg );
 
            player = new YouTubePlayer();
 
            player.autoPlay = true;
            player.playerWidth = 550;
            player.playerHeight = 350;
            player.x = 25;
            player.y = 25;
 
            addChild( player );
 
            closeButton.buttonMode = true;
            closeButton.filters = [ new GlowFilter( 0x000000, 1, 10, 10 ) ];
            closeButton.x = 560;
            closeButton.y = 15;
 
            closeButton.addEventListener( MouseEvent.CLICK, close );
 
            addChild( closeButton );
 
            visible = false;
        }
 
        public function play(videoId:String):void
        {
            player.init( videoId );
 
            visible = true;
        }
 
        public function close(e:*=null):void
        {
            player.stop();
 
            visible = false;
        }
    }
}

Как видите, я начинаю с создания плеера YouTube, все в функции init () и оставляю класс невидимым. Я также использовал другой актив SWC под названием «CloseButtonAsset». Затем у нас есть две основные функции «play ()» и «stop ()», и они делают именно то, что написано на жестяной коробке.

Теперь, когда мы довольны своим мнением игроков, мы можем продолжить с посредником.

Опять же, этот посредник не будет таким сложным, как вы думаете. Все, что он собирается сделать, это прослушать уведомление «PlayerView.PLAY» и показать игроку:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.flashtuts.view
{
    import com.flashtuts.view.component.PlayerView;
 
    import org.puremvc.as3.interfaces.IMediator;
    import org.puremvc.as3.interfaces.INotification;
    import org.puremvc.as3.patterns.mediator.Mediator;
 
    public class PlayerViewMediator extends Mediator implements IMediator
    {
        public static const NAME:String = 'PlayerViewMediator';
 
        private var playerView:PlayerView;
 
        public function PlayerViewMediator(viewComponent:Object=null)
        {
            super( NAME, viewComponent );
        }
 
        override public function onRegister():void
        {
            playerView = new PlayerView();
 
            viewComponent.addChild( playerView );
        }
 
        override public function listNotificationInterests():Array
        {
            return [
                PlayerView.PLAY
            ];
        }
 
        override public function handleNotification(notification:INotification):void
        {
            var name:String = notification.getName();
            var body:Object = notification.getBody();
 
            switch ( name )
            {
                case PlayerView.PLAY:
                playerView.play( body.videoId );
 
                break;
            }
        }
    }
}

We’re nearly at the end, but if you’ve been paying attention you’ll see that we haven’t yet added the results view mediator or the player view mediator to our application yet. This is because they’re not needed at the start of the application, for example, the results view mediator is only needed once a query is being run and the player view mediator is only needed once the results are in and ready to be clicked on. Our application mediator will control all of this, so launch «ApplicationMediator.as» — we’re going to update the «listNotificationInterests()» and «handleNotification()» functions like so:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.flashtuts.view
{
    import com.flashtuts.view.component.SearchView;
 
    import org.puremvc.as3.interfaces.IMediator;
    import org.puremvc.as3.interfaces.INotification;
    import org.puremvc.as3.patterns.mediator.Mediator;
 
    public class ApplicationMediator extends Mediator implements IMediator
    {
        public static const NAME:String = 'ApplicationMediator';
 
        public function ApplicationMediator(viewComponent:Object=null)
        {
            super( NAME, viewComponent );
        }
 
        override public function onRegister():void
        {
            facade.registerMediator( new ProgressViewMediator( viewComponent ) );
            facade.registerMediator( new SearchViewMediator( viewComponent ) );
        }
 
        override public function listNotificationInterests():Array
        {
            return [
                SearchView.SEARCH_RUN,
                SearchView.SEARCH_RESULTS
            ];
        }
 
        override public function handleNotification(notification:INotification):void
        {
            var name:String = notification.getName();
            var body:Object = notification.getBody();
 
            switch ( name )
            {
                case SearchView.SEARCH_RUN:
                if ( !facade.hasMediator( ResultsViewMediator.NAME ) )
                {
                    facade.registerMediator( new ResultsViewMediator( viewComponent ) );
                }
 
                break;
 
                case SearchView.SEARCH_RESULTS:
                if ( !facade.hasMediator( PlayerViewMediator.NAME ) )
                {
                    facade.registerMediator( new PlayerViewMediator( viewComponent ) );
                }
 
                break;
            }
        }
    }
}

You’ll see that we’re only registering the mediators at certain points during the user’s interaction with the application.

And we’ve done it! Fire up the application and let’s have a look..

Так что у вас есть это. Using the agility of PureMVC and the YouTube Player API tutorial you can now expand this little application to do many things or integrate the code into a bigger application or web site. The biggest help is Google’s GData API service, ever since they’ve pushed it to YouTube, querying the service has become easier and easier. It’s worth having a read of the GData docs as there are lots of things that can be done with Google’s products, such as uploading videos to YouTube, using Picasa APIs and Calendar APIs.

Thanks for following along.