2008年3月アーカイブ

こんにちは
flex builder でちょっとしたアプリを作ったのでそれの作り方をまとめてみました。
flex をこれから始める人、始めたけど
今ひとつコツがつかめず挫折した人。などの人に参考になればと。

で、今回何を作ったかというと、
「youtube が検索できる player 付きのアプリ」
です。この中に flex で一通りの使い方が色々と盛り込まれているので
一通り理解できれば、色んなアプリを手助けになるのではと思います。

さて、早速、完成画面から。今回はこんなのを作ってみようと思います。

見たい動画を検索窓に入れて、検索ボタンをおすと、左側のリストにyoutubeの検索結果が
サムネイル付きで表示されます。ここでは youtube の APIを利用して
検索結果を取得しています。
次にサムネイルをダブルクリックすると、右側のプレイヤーで動画が再生されます。
これだけです。

それでは、早速始めましょう。


まずは flex builder の体験版をダウンロードしましょう。
adobe flexの HP よりDownload free trial を
選択し、flex builder3の体験版をダウンロードしましょう。
60日間トライアルできます。
私はmac版をダウンロードしましたが、
windowsの方はwindows版をdownloadです。




次にdownloadしたファイルをPCにインストールします。
この部分の説明は割愛.


インストールが終わったらflex builderを起動します。

これから作成するアプリのプロジェクトを作成します.
メニューから[ファイル] - [新規] - [MXMLアプリケーション] を選択します

プロジェクト名を入力します。今回は youtube_player としました。


終了を押すと、元の画面にプロジェクトのひな形が作成されました。
ここから開発をスタートします。
左上のflexナビゲータには各種リソースがあります。
src/youtube_player.mxmlのソースに編集を加えていくことになります。
右のメイン画面にはそのソースが開いた状態になっていると思います。

次にまずはデザインを配置してしまいましょう。今回使う主要なものは
- キーワードを入力する TextInput
- 検索ボタンの Button
- 検索結果を表示する TileList
- 動画を見せる player
基本的にこの4つがあれば、デザインはどんなものでも良いです。
メインパネルの「ソース」と「デザイン」の切り替えで「デザイン」を押して
作ります。(もちろんソースに直に書いてもokです). 私が行った方法を例にあげます


Application(全体) の レイアウトを vertical にする.
ApplicationControlBar を配置し width:100% にする.
その中に TextInput と Button を配置する.
Button のラベルを youtube search にする
次にApplicationControlBarの下部にHDividedBoxを配置する
width:100% height:100%にする
その中に TileList を width:100% height:100%で配置する

この時点で youtube_player.mxmlのソースは

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
    <mx:ApplicationControlBar width="100%">
        <mx:TextInput/>
        <mx:Button label="youtube search"/>
    </mx:ApplicationControlBar>
    <mx:HDividedBox width="100%" height="100%">
        <mx:TileList width="100%" height="100%"></mx:TileList>
    </mx:HDividedBox>
</mx:Application>
となっています.

では、ちょっとずつ確認しながら作りましょう.
まず TextInputにキーワードを入力して Buttonをクリックしたら Alertがあがるようにしましょう。
そのためには、TextInput に id をつけて Button のクリック動作に関数を割り当てましょう.


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
    <mx:Script>
        <![CDATA[
            import mx.controls.Alert;
            public function send_request():void {
                Alert.show(keyword.text);
            }
        ]]>
    </mx:Script>
    <mx:ApplicationControlBar width="100%">
        <mx:TextInput id="keyword" />
        <mx:Button label="youtube search" click="send_request()"/>
    </mx:ApplicationControlBar>
    <mx:HDividedBox width="100%" height="100%">
        <mx:TileList width="100%" height="100%"></mx:TileList>
    </mx:HDividedBox>
</mx:Application>

なにをやったかというと, TextInput に keywordというidを与え、Buttonの click イベントに send_request の関数を与えました。
mx:Script のタグをあたらにもうけ、その中に send_requestの関数を処理を記入しました。
今回は keywordの中身の文字列のAlert を出すのでその処理を記入しました。
(Alertを出すには mx.controls.Alert を import する必要があるのでそれも加えてあります)


ここで実行を一度してみましょう。flex builder上部の緑色の丸いプレイアイコンをクリックするか 実行メニューを選ぶとswfをコンパイルしてブラウザが勝手に起動されると思います。 そこに先ほどデザインしたものが表示され、キーワード窓に適当に入力し、ボタンをクリックしたら Alertダイアログが表示されその中身はキーワード窓で入力したものが表示されていると思います。


さて、次に youtube APIを利用して動画リストを取得するのですが、 youtube APIの仕様を確認しておきましょう. APIにはさまざまなリクエスト方法がありますが、今回使用するのは単純にキーワード検索ですので

http://gdata.youtube.com/feeds/api/videos?vq=[キーワード]
です。実際にブラウザでアクセスしてみるとXMLが取得できると思います.
flexにてapiにアクセスする一般的な方法は HTTPServiceを利用することです。先ほどの youtube_player.mxml に

    <mx:HTTPService id="youtubeapi" 
             url="http://gdata.youtube.com/feeds/api/videos" method="GET"
             result="youtubeapi_result(event)" />
をまず加えます. 次に先ほど Alertをだしていた関数にsend_request にAPIリクエストを投げる処理を加え、APIの応答が戻ってきたときに呼ばれる(HTTPService関数のresultで指定した)youtubeapi_result関数を作れば、youtubeAPIに flexからリクエストを投げて応答を受け取ったことになります. ここまでで プログラムは以下になります

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
    <mx:Script>
        <![CDATA[
            import mx.rpc.events.ResultEvent;
            import mx.controls.Alert;
            public function send_request():void {
                var uv:URLVariables = new URLVariables;
                uv.vq = keyword.text;
                youtubeapi.request = uv;
                youtubeapi.send();
            }
            
            public function youtubeapi_result(event:ResultEvent):void {
                Alert.show("get youtube result");
            }
        ]]>
    </mx:Script>
    <mx:ApplicationControlBar width="100%">
        <mx:TextInput id="keyword" />
        <mx:Button label="youtube search" click="send_request()"/>
    </mx:ApplicationControlBar>
    <mx:HDividedBox width="100%" height="100%">
        <mx:TileList width="100%" height="100%"></mx:TileList>
    </mx:HDividedBox>
    
    <mx:HTTPService id="youtubeapi" 
                    url="http://gdata.youtube.com/feeds/api/videos" method="GET"
                    result="youtubeapi_result(event)" />
                    
</mx:Application>

説明していない部分は, send_request の中の

        var uv:URLVariables = new URLVariables;
        uv.vq = keyword.text;
        youtubeapi.request = uv;
        youtubeapi.send();
ですが、 URLVariables クラスを用いると一般的なAPIの引数の &key1=val1&key2=val2 値を 一つの変数で保持できます. 今回は vq=キーワードなので uv.vq = キーワード となります. 後はこの変数を HTTPServiceの request にセットして APIに投げます (send).
ここでもう一度実行してみてください。 検索ボタンをおしてしばらく待つと応答が帰ってくると思います.
さて、youtube からの応答がXML帰ってきました。が中身を知らなければ何もできません. ブラウザでアクセスしてみて応答をソース表示して中身のXMLを一度確認してみましょう. かなり、よーくみると以下の構造をしていることが分かります

<?xml version='1.0' encoding='UTF-8'?>
<feed .....>
しばらく、ヘッダー的なタグが続く
<entry>1件目の動画情報<entry>
<entry>2件目の動画情報<entry>
<entry>3件目の動画情報<entry>
<entry>....<entry>
<entry>n件目の動画情報<entry>
</feed>
さらに、entryの中身は

<entry>
  <id>http://gdata.youtube.com/feeds/api/videos/_EEx3VhloNg</id>
  <published>2007-07-08T04:04:05.000-07:00</published>
  <updated>2007-07-08T04:04:05.000-07:00</updated>
  <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='15年目'/>
  <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='YUTAKA'/>
  <category scheme='http://schemas.google.com/g/2005#kind' term='http://gdata.youtube.com/schemas/2007#video'/>
  <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='尾崎豊'/>
  <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='OZAKI'/>
  <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='卒業'/>
  <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='アイラブユー'/>
  <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat' term='Music' label='Music'/>
  <title type='text'>尾崎豊 - 卒業</title>
  <content type='text'>尾崎豊 15年目のアイラブユー
2007-04-28
from Japan</content>
  <link rel='alternate' type='text/html' href='http://www.youtube.com/watch?v=_EEx3VhloNg'/>
  <link rel='http://gdata.youtube.com/schemas/2007#video.responses' type='application/atom+xml' href='http://gdata.youtube.com/feeds/api/videos/_EEx3VhloNg/responses'/>
  <link rel='http://gdata.youtube.com/schemas/2007#video.related' type='application/atom+xml' href='http://gdata.youtube.com/feeds/api/videos/_EEx3VhloNg/related'/>
  <link rel='self' type='application/atom+xml' href='http://gdata.youtube.com/feeds/api/videos/_EEx3VhloNg'/>
  <author>
    <name>sean1965jp</name>
    <uri>http://gdata.youtube.com/feeds/api/users/sean1965jp</uri>
  </author>
  <media:group>
    <media:title type='plain'>尾崎豊 - 卒業</media:title>
    <media:description type='plain'>尾崎豊 15年目のアイラブユー
2007-04-28
from Japan</media:description>
    <media:keywords>15年目, OZAKI, YUTAKA, アイラブユー, 卒業, 尾崎豊</media:keywords>
    <yt:duration seconds='411'/>
    <media:category label='Music' scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>Music</media:category>
    <media:content url='http://www.youtube.com/v/_EEx3VhloNg' type='application/x-shockwave-flash' medium='video' isDefault='true' expression='full' duration='411' yt:format='5'/>
    <media:content url='rtsp://rtsp2.youtube.com/ChoLENy73wIaEQnYoGVY3TFB_BMYDSANFEgGDA==/0/0/0/video.3gp' type='video/3gpp' medium='video' expression='full' duration='411' yt:format='1'/>
    <media:content url='rtsp://rtsp2.youtube.com/ChoLENy73wIaEQnYoGVY3TFB_BMYESARFEgGDA==/0/0/0/video.3gp' type='video/3gpp' medium='video' expression='full' duration='411' yt:format='6'/>
    <media:player url='http://www.youtube.com/watch?v=_EEx3VhloNg'/>
    <media:thumbnail url='http://img.youtube.com/vi/_EEx3VhloNg/2.jpg' height='97' width='130' time='00:03:25.500'/>
    <media:thumbnail url='http://img.youtube.com/vi/_EEx3VhloNg/1.jpg' height='97' width='130' time='00:01:42.750'/>
    <media:thumbnail url='http://img.youtube.com/vi/_EEx3VhloNg/3.jpg' height='97' width='130' time='00:05:08.250'/>
    <media:thumbnail url='http://img.youtube.com/vi/_EEx3VhloNg/0.jpg' height='240' width='320' time='00:03:25.500'/>
  </media:group>
  <yt:statistics viewCount='195171'/>
  <gd:rating min='1' max='5' numRaters='133' average='4.95'/>
  <gd:comments>
    <gd:feedLink href='http://gdata.youtube.com/feeds/api/videos/_EEx3VhloNg/comments' countHint='0'/>
  </gd:comments>
</entry>
それでは、flexからこのXMLの各要素にアクセスしてみましょう。簡単です。応答が帰ってきたときに 呼ばれるために作った関数 youtubeapi_resultの引数に event:ResultEvent があります。これの event.result要素がこのXMLになります。なので、例えば entryの5件目のtitle は

event.result.feed.entry[5].group.title
になります。それでは、ひとまず正しくXMLを取得できているか確認するために youtubeapi_result関数を

    public function youtubeapi_result(event:ResultEvent):void {
        Alert.show(event.result.feed.entry.length);
        for(var i:int=0;i<event.result.feed.entry.length;i++) {
            Alert.show(event.result.feed.entry[i].group.title);
        }
    }
として動作確認してみてください。取得した動画の本数とタイトルが順にAlertに表示されると思います.

さて、次はこの結果をTileListにリスト表示させます List, TileList, HorizontalList などの各要素は単純に dataProviderを用いてリスト表示をするのが単純な使い方ですが (flexリファレンス) 検索結果画面とか商品一覧とかの画面ではリストの一つ一つがUIデザインをもつものであることが多いです。そのために、この List系のコンポーネントは itemRenderer というプロパティをもちます。これを使えば、個々のItemの設計を別に定義できます (flexリファレンス)
文字で書くと良くわからないので実際にやってみます。
まず、TileList のタグを

<mx:TileList width="100%" height="100%" dataProvider="{movielist}" itemRenderer="movieitem"
とします. これの意味は TileListの要素はmovielistの変数の値を使うよ. 個々のitemの表示には movieitemコンポーネント (movieitem.mxml) を使うよ. という意味です. movielist (ArrayCollection) も加えた形は下記になります (movielistは Bindable として登録する必要があります). youtubeapi_resultの処理をmovielistの初期化および entry リストの代入を行うように変更しました.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
    <mx:Script>
        <![CDATA[
            import mx.rpc.events.ResultEvent;
            import mx.controls.Alert;
            import mx.collections.ArrayCollection;

            [Bindable]
            public var movielist:ArrayCollection = new ArrayCollection;    

            public function send_request():void {
                var uv:URLVariables = new URLVariables;
                uv.vq = keyword.text;
                youtubeapi.request = uv;
                youtubeapi.send();
            }
            
            public function youtubeapi_result(event:ResultEvent):void {
                movielist.removeAll();
                for(var i:int=0;i<event.result.feed.entry.length;i++) {
                    movielist.addItem(event.result.feed.entry[i]);
                }
            }
        ]]>
    </mx:Script>
    <mx:ApplicationControlBar width="100%">
        <mx:TextInput id="keyword" />
        <mx:Button label="youtube search" click="send_request()"/>
    </mx:ApplicationControlBar>
    <mx:HDividedBox width="100%" height="100%">
        <mx:TileList width="100%" height="100%" dataProvider="{movielist}" itemRenderer="movieitem" />
    </mx:HDividedBox>
    
    <mx:HTTPService id="youtubeapi" 
                    url="http://gdata.youtube.com/feeds/api/videos" method="GET"
                    result="youtubeapi_result(event)" />
                    
</mx:Application>
さて、これで実行するとエラーになるはずです. movieitem って何ですか? と怒られてしまいます。 ので、movieitem を作りましょう.

[ファイル] - [新規] - [MXMLコンポーネント] を選択して


ファイル名: movieitem ベース: VBox 幅: 150 高さ:150
で終了すれば movieitem.xml が左上の flexナビゲータに追加されます. この状態で実行するとエラーにはなりません. がまだ何も表示されません が、マウスでTileListをなぞるとitemが置かれている予感がします.

さて、 movielist.xml の記述に入ります. メインの画面を movielist.mxmlに切り替えて Image および Text を配置します。デザインから行っても構いませんが、最終的なソースは

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="150" height="150"  horizontalAlign="center">
    <mx:Image height="97" width="130" source="{data.group.thumbnail.getItemAt(0).url}"/>
    <mx:Text  text="{data.group.title}" width="100%" height="100%"/>  
</mx:VBox>
になります. Imageはイメージ画像をロードするコンポーネントです. ここで重要なのが, TileListのdataProviderの各要素がこのコンポーネントに渡されるのですが、その各要素は data の変数から 取得できるということです. なので youtube の entry を各要素として TileListのdataProviderに渡しているからこの中では entryのtitleは data.group.title で取得できます. 1つめのサムネイル画像は data.group.thumbnail.getItemAt(0).url で取得できます (data.group.thumbnail[0].urlとするとバインディングエラーがでるので注意).

ここで実行してみましょう

ひとまずやった!ですね。
ということで応用すれば TileList をほかのに変更すれば縦リスト、横リスト. それに応じてまだ使ってない entryの要をを movieitem.mxml に貼付けていけばどんどんオリジナルな画面になっていきます.

さて、次は player の部分です。そもそもflexで動画を流すのは flv 形式のファイルをVideoDisplayというコンポーネントで再生する形にします. youtubeの各動画のflv形式を取得するのは、まず個々のvideo_idを取得します。これは普通にyoutubeを見るときにURLの中に含まれているので一般的です. APIのXMLの中にも

<entry>
  <id>http://gdata.youtube.com/feeds/api/videos/_EEx3VhloNg</id>
とあります。この_EEx3VhloNgがvideo_idです。 で、これが分かったら次に こういうホームページの解説をフムフムと参考にさせていただいて, 自前のサーバにちょっとflexからはなれて、

<?php
    $curl = curl_init();
    curl_setopt ($curl, CURLOPT_URL, "http://www.youtube.com/watch?v=${_GET['video_id']}");
    curl_setopt ($curl, CURLOPT_RETURNTRANSFER, 1);
    $html = curl_exec ($curl);

    preg_match('|"video_id": "(.*?)"|', $html, $v);
    preg_match('|"t": "(.*?)"|', $html, $t);

    print "<url>";
    print "http://jp.youtube.com/get_video?video_id=${v[1]}&t=${t[1]}";
    print "</url>";
?>
こんなPHPスクリプトを設置します. これは何かというと
http://hiyuzawa.jpn.org/api/youtube.php?video_id=_EEx3VhloNg とすれば

<url>
http://jp.youtube.com/get_video?video_id=_EEx3VhloNg&t=OEgsToPDskJkG3phYIjT7JC2IvqXnU3a
</url>
が戻ってくるスクリプトです。この戻りのURLでflvが取得できます.
さて、検索結果のサムネイルをダブルクリックした場合に動画が再生されるようにしたいので、 まず、サムネイルのダブルクリックを検知し、関数が呼ばれる仕組みを実装しましょう.
TileListのプロパティに

doubleClickEnabled="true" doubleClick="playmovie()"
を加えます。 doubleClickEnabledを trueにするのを忘れないようにしてください。それで playmovie関数を定義すればそれが呼ばれます。今回はもう少し突っ込んで進みましょう。最終的に やりたいことはタブルクリックしたら
1. ダブルクリックしたサムネイルの video_idをしらべて
2.そのvideo_idを先ほどのflvが取得できるURLを獲得できる自作のapiに投げて
3.その応答のURLを動画再生のsourceにセットする
です。なので、1.のダブルクリックしたサムネイルのvideo_idまで取得できるように実装しましょう.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
    <mx:Script>
        <![CDATA[
            import mx.rpc.events.ResultEvent;
            import mx.controls.Alert;
            import mx.collections.ArrayCollection;

            [Bindable]
            public var movielist:ArrayCollection = new ArrayCollection;            

            public function send_request():void {
                var uv:URLVariables = new URLVariables;
                uv.vq = keyword.text;
                youtubeapi.request = uv;
                  youtubeapi.send();
            }
            
            public function youtubeapi_result(event:ResultEvent):void {
                movielist.removeAll();            
                for(var i:int=0;i<event.result.feed.entry.length;i++) {
                    movielist.addItem(event.result.feed.entry[i]);
                }
            }
            
            public function playmovie():void {
                var tmp:Array = movielist.getItemAt(tilelist.selectedIndex).id.split('/');
                var video_id:String = tmp[tmp.length-1];
                Alert.show(video_id);
            }
        ]]>
    </mx:Script>
    <mx:ApplicationControlBar width="100%">
        <mx:TextInput id="keyword" />
        <mx:Button label="youtube search" click="send_request()"/>
    </mx:ApplicationControlBar>
    <mx:HDividedBox width="100%" height="100%">
        <mx:TileList width="100%" height="100%" dataProvider="{movielist}" 
              itemRenderer="movieitem"
              doubleClickEnabled="true" doubleClick="playmovie()" 
              id="tilelist" />
    </mx:HDividedBox>
    
    <mx:HTTPService id="youtubeapi" 
                    url="http://gdata.youtube.com/feeds/api/videos" method="GET"
                    result="youtubeapi_result(event)" />
                    
</mx:Application>
playmovieの関数で, tilelist.selectedIndex が何番目の listを今選択しているかが取得できます. (TileListのidをtilelistにしました.) movielist.getItemAt(tilelist.selectedIndex).id でその選択している entryの idタグ部分が 取得できます。このidは
<id>http://gdata.youtube.com/feeds/api/videos/_EEx3VhloNg</id> となっている部分なので、実際のvideo_idは最後の/の後ろの部分なので、ちょっと横着して / でsplitして、最後の部分を取得しています. (この部分はもっといい方法があると思います。)
まあ、これで実行してサムネイルをダブルクリックしてみてください. video_idが表示されるはずです.

次にvideo_idが取得できたら、これを自作のAPIに投げて flvのURLが取得できるところまで実装しましょう。APIへのリクエスト&受信はまったくyoutube API の部分と同じ感じです。一気に実装します.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
    <mx:Script>
        <![CDATA[
            import mx.rpc.events.ResultEvent;
            import mx.controls.Alert;
            import mx.collections.ArrayCollection;

            [Bindable]
            public var movielist:ArrayCollection = new ArrayCollection;            

            public function send_request():void {
                var uv:URLVariables = new URLVariables;
                uv.vq = keyword.text;
                youtubeapi.request = uv;
                  youtubeapi.send();
            }
            
            public function youtubeapi_result(event:ResultEvent):void {
                movielist.removeAll();            
                for(var i:int=0;i<event.result.feed.entry.length;i++) {
                    movielist.addItem(event.result.feed.entry[i]);
                }
            }
            
            public function playmovie():void {
                var tmp:Array = movielist.getItemAt(tilelist.selectedIndex).id.split('/');
                var video_id:String = tmp[tmp.length-1];
                var uv:URLVariables = new URLVariables;
                uv.video_id = video_id;
                flvurlapi.request = uv;
                flvurlapi.send();                
            }
            private function flvurlapi_result(event:ResultEvent):void {
                Alert.show(event.result.url);
            }
        ]]>
    </mx:Script>
    <mx:ApplicationControlBar width="100%">
        <mx:TextInput id="keyword" />
        <mx:Button label="youtube search" click="send_request()"/>
    </mx:ApplicationControlBar>
    <mx:HDividedBox width="100%" height="100%">
        <mx:TileList width="100%" height="100%" dataProvider="{movielist}"
             itemRenderer="movieitem" doubleClickEnabled="true" doubleClick="playmovie()" 
             id="tilelist" />
    </mx:HDividedBox>
    
    <mx:HTTPService id="youtubeapi" 
                    url="http://gdata.youtube.com/feeds/api/videos" method="GET"
                    result="youtubeapi_result(event)" />
                    
    <mx:HTTPService id="flvurlapi" 
                    url="http://hiyuzawa.jpn.org/api/youtube.php" method="GET"
                    result="flvurlapi_result(event)" />
</mx:Application>
同じですね. もう一つ HTTPServiceをつくって、ダブルクリックで呼ばれる関数で send して 応答を受信する。event.result.url で <url>http://......</url>の中身が取得できます.

さあ、次にplayerを作ります。playerは VideoDisplayという 非常に便利なコンポーネントがありますのでこれを使います. 実は単にメインの画面にこの VideoDisplayを 設置して id="hogehoge" とつけて hogehoge.source = で先ほどのflv のURLをセットすればそれで 再生できてしまうのですが... それだと応用性に欠けるのでplayerを独立したモジュールで作ってみましょう。さっさと再生したい方は上の方法をトライしてみてください.

flvのplayerは別につくるアプリでも使う可能性がある. とか、 再生とか停止とかタイムとかそういうデザインをメインのmxmlに加えると混乱するなどという場合に mxmlファイルを別に定義してそれを読み込む形ができます。ちょうど上の itemRenderer と似ているような感じです。早速playerを独立したmxmlファイルで定義してみましょう.
まず、左上のflexナビゲータのsrcのフォルダを右クリックして「新規」-「フォルダー」で module という名前のフォルダーを作ってください. 実際にはこの名前は何でもいいです.
次に, 先ほどの movieitem.mxmlを作っときと同様にメニューから
「ファイル」-「新規」-「MXMLコンポーネント」を選びます.
ファイル名: player ベース: VBox 幅: 250 高さ:250
とします.作成先が module のフォルダの下になるように設定してください.

最終的には左のようになればokです

さて、ではこのplayer.mxmlに 動画プレイヤーの各機能を作っていきます。
一般的な動画再生サイトのplayerはカッコいい停止再生ボタンや、音量調節、再生ヘッド位置とか 色々表示されていますが、今回はUI的なことに凝ると本題から外れるので最低限の以下の機能&情報を 表示することにしましょう.
- 動画再生画面
- 中断/再生ボタン
- 読み込み済みbyte数 と Total byte数
- 再生の経過時間 と Total再生時間
です。

とりあえず上の情報を並べると、例えば

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" 
    width="250" height="250">
    <mx:Label text="my youtube player"/>
    <mx:VideoDisplay id="vd" width="100%" height="100%" />
    <mx:HBox>
        <mx:Button label="play" />
        <mx:Button label="stop" />    
    </mx:HBox>
    <mx:HBox>
        <mx:Label text="Loading Info:" />
        <mx:Label id="byteloaded" />
        <mx:Label text="/" />
        <mx:Label id="bytetotal" />
    </mx:HBox>
    <mx:HBox>
        <mx:Label text="Playing Info:" />
        <mx:Label id="playtime" />
        <mx:Label text="/" />
        <mx:Label id="totaltime" />
    </mx:HBox>
</mx:VBox>

という風になります。idは必要な箇所にすでに割り当てました.動画プレイヤー風になるように デザインビューなどをみてみて調節ください.

さて、このプレイヤーを本体 (youtube_player.mxml) に設置するにはどうすればいいでしょう.
説明するのより、見てもらった方が理解しやすいのでそのまま貼付けます

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:module="module.*" layout="vertical">
    <mx:Script>
        <![CDATA[
            import mx.rpc.events.ResultEvent;
            import mx.controls.Alert;
            import mx.collections.ArrayCollection;

            [Bindable]
            public var movielist:ArrayCollection = new ArrayCollection;            

            public function send_request():void {
                var uv:URLVariables = new URLVariables;
                uv.vq = keyword.text;
                youtubeapi.request = uv;
                  youtubeapi.send();
            }
            
            public function youtubeapi_result(event:ResultEvent):void {
                movielist.removeAll();            
                for(var i:int=0;i<event.result.feed.entry.length;i++) {
                    movielist.addItem(event.result.feed.entry[i]);
                }
            }
            
            public function playmovie():void {
                var tmp:Array = movielist.getItemAt(tilelist.selectedIndex).id.split('/');
                var video_id:String = tmp[tmp.length-1];
                var uv:URLVariables = new URLVariables;
                uv.video_id = video_id;
                flvurlapi.request = uv;
                flvurlapi.send();                
            }
            private function flvurlapi_result(event:ResultEvent):void {
                Alert.show(event.result.url);
            }
        ]]>
    </mx:Script>
    <mx:ApplicationControlBar width="100%">
        <mx:TextInput id="keyword" />
        <mx:Button label="youtube search" click="send_request()"/>
    </mx:ApplicationControlBar>
    <mx:HDividedBox width="100%" height="100%">
        <mx:TileList width="100%" height="100%" dataProvider="{movielist}" itemRenderer="movieitem" doubleClickEnabled="true" doubleClick="playmovie()" id="tilelist" />
        <module:player id="flvplayer" />
    </mx:HDividedBox>
    
    <mx:HTTPService id="youtubeapi" 
                    url="http://gdata.youtube.com/feeds/api/videos" method="GET"
                    result="youtubeapi_result(event)" />
                    
    <mx:HTTPService id="flvurlapi" 
                    url="http://hiyuzawa.jpn.org/api/youtube.php" method="GET"
                    result="flvurlapi_result(event)" />
                    
</mx:Application>
名前空間がどうこうという説明を本来するのでしょうが、こうやって上部におまじない書くと、そのフォルダ内のmxmlファイルを読み込むことができますよ。その際は通常 mx:hoge と書いている部分を module:hoge という風にするんですよ。と覚えておいてください
さて、これで実行してみてください。基本のロジックは変えていませんが、一番最初に HDividedBox を設置してから右側に何も無かった部分にplayer.mxmlで定義したモジュールが加わったことでしょう.
後もう少しです。まずは、とっととダブルクリックで再生できるようにまずはしてしまいましょう. playerで定義した VideoDisplayのsourceに先ほどAPIで取得した flv のURLをセットすれば再生されます.
これをどのように実装するかは下記になります. Bindable で 変数 flvurl を定義しそれを VideoDisplayの sourceにセットする. こうすると youtube_player.mxml で先ほど定義した flvplayer から flvplayer.flvurl でアクセスできます.
player.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="250" height="250">
    <mx:Script>
        <![CDATA[
            [Bindable]
            public var flvurl:String = new String;  
        ]]>
    </mx:Script>
    <mx:Label text="my youtube player" />
    <mx:VideoDisplay id="vd" width="100%" height="100%" source="{flvurl}"/>
    <mx:HBox>
        <mx:Button label="play" />
        <mx:Button label="stop" />    
    </mx:HBox>
    <mx:HBox>
        <mx:Label text="Loading Info:" />
        <mx:Label id="byteloaded" />
        <mx:Label text="/" />
        <mx:Label id="bytetotal" />
    </mx:HBox>
    <mx:HBox>
        <mx:Label text="Playing Info:" />
        <mx:Label id="playtime" />
        <mx:Label text="/" />
        <mx:Label id="totaltime" />
    </mx:HBox>
</mx:VBox>
youtube_player.xml の一部

            private function flvurlapi_result(event:ResultEvent):void {
                flvplayer.flvurl = event.result.url;
            }
実行してみてください。 検索してサムネイルをダブルクリックすると動画がplayerで再生されます.

実はこれで youtube_player.mxml は終わりです。playerの装飾は全部player.mxml の中で実装されます.

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="250" height="250" creationComplete="init()">
    <mx:Script>
        <![CDATA[
            import mx.events.VideoEvent;
            [Bindable]
            public var flvurl:String = new String;
            
            private function init():void {
                vd.addEventListener(ProgressEvent.PROGRESS, function():void {
                    byteloaded.text = vd.bytesLoaded.toString();            
                    bytetotal.text  = vd.bytesTotal.toString();
                    playtime.text   = vd.playheadTime.toString();
                    totaltime.text  = vd.totalTime.toString();
                });
                vd.addEventListener(VideoEvent.PLAYHEAD_UPDATE, function():void {
                    byteloaded.text = vd.bytesLoaded.toString();            
                    bytetotal.text  = vd.bytesTotal.toString();
                    playtime.text   = vd.playheadTime.toString();
                    totaltime.text  = vd.totalTime.toString();
                });
            }
        ]]>
    </mx:Script>
    <mx:Label text="my youtube player" />
    <mx:VideoDisplay id="vd" width="100%" height="100%" source="{flvurl}"/>
    <mx:HBox>
        <mx:Button label="play" click="vd.play()"/>
        <mx:Button label="stop" click="vd.pause()"/>    
    </mx:HBox>
    <mx:HBox>
        <mx:Label text="Loading Info:" />
        <mx:Label id="byteloaded" />
        <mx:Label text="/" />
        <mx:Label id="bytetotal" />
    </mx:HBox>
    <mx:HBox>
        <mx:Label text="Playing Info:" />
        <mx:Label id="playtime" />
        <mx:Label text="/" />
        <mx:Label id="totaltime" />
    </mx:HBox>
</mx:VBox>
playとstop(pause)のボタンへの割当は上の要領でok. あとは 動画読み込み中、再生中に 各種データ(読み込みbyte, 再生時間の更新をするために, VideoDisplayの addEventListener の
- ProgressEvent.PROGRESS = FLV ファイルが完全にダウンロードされるまで継続的に送出されます。
- VideoEvent.PLAYHEAD_= UPDATE ビデオの再生中に 0.25 秒ごとに送出されます
というイベントでUpdate通知させます. 各種情報は VideoDisplayのリファレンスから抜き出せばもっとリッチなplayerがつくれます.

さて、長々説明してきた Flex builder で作る youtubeが検索できるplayer付きアプリ もこれで完成しました。完成系は





こんな感じになったと思います.
かなり我流な感じもしますので、ちゃんとしたflexの参考書からみれば間違った解説している可能性が 多くある気がしますが、その辺はご了承ください.
それでは長々とお付き合い下さいましてありがとうございました。

このアーカイブについて

このページには、2008年3月に書かれたブログ記事が新しい順に公開されています。

前のアーカイブは2008年1月です。

次のアーカイブは2008年9月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

Powered by Movable Type 4.0