WEBOPIXEL

Flashで作るアニメーションで切り替わるTwitterウィジェット

Posted: 2010.08.20 / Category: ActionScript / Tag: ,

以前、jQueryでTwitterのつぶやきを取得するという記事を書きましたが、それのFlash版をチュートリアル形式でお送りします。
ただ表示するだけじゃつまらないかと思いますので、Flashらしくアニメーションとかもつけてみます。

Sponsored Link

demo

画像の作成

画像を準備するところからはじめましょう。
Flashで作成してもいいし、PhotoShopなどの画像編集ソフトで作ってもいいです。
今回はこんな2つの画像を用意しました。

画像サンプル

「frame.png」はウィジェットの枠となる画像です。真ん中の縞々の部分は透明という意味です。なのでpng32で保存します。
「panel.png」は文字の部分の背景に表示される画像です。透明度はないので保存形式は何でもいいですが、ここではpng形式で保存しました。

PHPでTwitterのつぶやきを取得する

Flashで作ると言いつつTwitterからの情報の取得はPHPで行います。
Flashだけでも可能ですが、クロスドメインポリシーの関係でいろいろ面倒なことをしなくてはいけないらしいです。
なのでこの部分はサーバースクリプトに任せた方が簡単だと思います。

load.php

		<?php
			$req = @file_get_contents('http://twitter.com/statuses/user_timeline/[ユーザー名].xml');
			header("Content-Type: application/xml");
			echo $req;
		?>
	

utf-8で「load.php」という名前で保存します。
当然ですがURLの[ユーザー名]は自身のものに置き換えてください。
またURLの後ろにパラメータを設定することで取得する条件を指定することができます。
たとえば「[ユーザー名].xml?count=5」で5だけツイートを取得できます。
詳しくは下記Twitter APIをご確認ください。

Twitter API 仕様書 日本語訳

Flashで作成した画像を読み込み

エクスプローラーから作成した画像をFlashにドラッグするか、「ファイル」→「読み込み」→「ライブラリに読み込み」で画像を読み込みます。
次にリンケージ設定を行います。
ライブラリに読み込まれたアイテムを右クリックし「リンケージ」を選択します。リンケージプロパティウインドウが表示されたらクラス名を設定します。
ここでは「frame.png」をクラス名「Frame」に、「panel.png」を「Panel」としました。
これでActionScriptからライブラリのアイテムにアクセスできるようになります。

リンケージ設定画面

ステージサイズは「frame.png」と同じにしておきます。
ドキュメントクラスも忘れず設定しておきましょう。ここでは「Main」とします。これで準備は完了です。

PHPからつぶやきを取得して切り替えるスクリプト

もしかしたらアニメーションなんていらねーって人もいるかもしれないので、まずは表示されたつぶやきを単純に切り替えるだけのものを作りたいと思います。
とりあえずグローバル変数と全体のメソッドです。

Main.as

			package
			{
				import flash.display.Sprite;
				import flash.net.URLLoader;
				import flash.net.URLRequest;
				import flash.events.Event;
				import flash.events.IOErrorEvent;
				import flash.text.TextField;
				import flash.text.TextFieldType;
				import flash.utils.Timer;
				import flash.events.TimerEvent;
				import flash.display.BitmapData;
				import flash.display.Bitmap;
			
				public class Main extends Sprite
				{
					var _textArray:Array;		//テキストフィールドを入れる配列
					var _textContainer:Sprite;	//ツイートを入れるコンテナ
					var _currentNo:uint;		//現在のNo
					var _timerObj:Timer;		//ツイート切り替えのタイマー
					var _txtWidth:uint;			//テキストの横幅
					var _panelHeight:uint;		//パネルを縦幅
					
					public function Main() {}
					
					/* *****************************************
					RSS取得失敗時の処理
					****************************************** */
					public function ioError(event:IOErrorEvent):void {}
			
					/* *****************************************
					RSSロード完了後の処理
					****************************************** */
					public function loadComp(event:Event):void {}
					
					/* *****************************************
					タイマー処理(一定時間で次のツイート)
					****************************************** */
					function timerEvent(event:Event):void {}
				}
			}
		

コンストラクタで作成したphpファイルを読み込み、ロード完了後にツイートを表示します。タイマーイベントではツイートを切り替えます。

function Main – Main.as

			public function Main()
			{
				var xmlURL:String = "load.xml";	//PHPファイルの指定
				_timerObj = new Timer(5000);	//切り替えの時間設定
				_currentNo = 0;	//現在のツイート(最初は0)
				_textArray = new Array();	//テキストフィールドを入れる配列
				_txtWidth = 260;		//テキストの横幅
				_panelHeight = 120;	//パネルの縦幅
		

コンストラクタ部分です。
ここでグローバル変数に対して初期設定を行っています。
「xmlURL」で作成したphpファイルのファイル名を指定します。
この場合同一のフォルダに入れることになりますが、フォルダが別の場合は変更してください。絶対パスにした方がいいかもしれません。
「_txtWidth」「_panelHeight 」はデザインによって調節してください。

function Main – Main.as

			//ライブラリからPanelを配置
			var panelData:BitmapData = new Panel(100, 100);
			var panelImg:Bitmap = new Bitmap(panelData);
			panelImg.x = 26;
			panelImg.y = 57;
			this.addChild(panelImg);
			
			//テキストコンテナを配置
			_textContainer = new Sprite();
			_textContainer.x = 33;
			_textContainer.y = 63;
			this.addChild(_textContainer);
			
			//ライブラリからFrameを配置
			var frameData:BitmapData = new Frame(100, 100);
			var frameImg:Bitmap = new Bitmap(frameData);
			this.addChild(frameImg);
		

Flashで読み込んだ画像の配置と、取得したツイートを入れるためのコンテナを配置しています。
addChildは順番が大事で、最初にaddChildしたものから順番にレイヤーを重ねたようになります。
なのでPanel→テキスト→Frameの順に追加していけばFrameが一番上になります。
これでテキスト部分を動かしても、表示されるのはFrameの透明の部分だけになります。

あとx,yの部分はやはりデザインによって調整してください。

addChildイメージ

function Main – Main.as

				//RSSのロード
				var xmlLoader:URLLoader = new URLLoader();
				xmlLoader.load(new URLRequest(xmlURL));
				//ロード完了時イベント
				xmlLoader.addEventListener(Event.COMPLETE, loadComp);
				//ロードエラー時イベント
				xmlLoader.addEventListener(IOErrorEvent.IO_ERROR, ioError);
			}
		

コンストラクタ最後の部分です。
ローダーと、ロード完了とエラー時のイベントリスナーです。

function ioError – Main.as

			public function ioError(event:IOErrorEvent):void
			{
				var error_txt = new TextField();
				error_txt.text = "RSSの取得に失敗しました。";
				error_txt.width = _txtWidth;
				_textContainer.addChild(error_txt);
			}
		

指定したload.phpが取得できなかった場合に「RSSの取得に失敗しました。」と表示されます。
でもこれだとTwitter本体のサイトがダウンしたときはエラーが表示されないかもしれない……
たぶんどっかでそれ用の処理をする必要があると思います。

function loadComp – Main.as

			public function loadComp(event:Event):void
			{
				//ロードしたXMLをrssに入れる
				var rss:XML = new XML(event.target.data);
				//ツイートの数だけテキストフィールドを作成
				var count:uint = 0;
				for each(var item:Object in rss.status.text) {
					_textArray.push(new TextField());
					_textArray[count].text = item;
					//横幅設定
					_textArray[count].width = _txtWidth;
					//折り返し設定ON
					_textArray[count].multiline = _textArray[count].wordWrap = true;
					count++;
				}
				//最初のツイートを表示
				_textContainer.addChild(_textArray[0]);
				//タイマーイベントスタート
				_timerObj.addEventListener(TimerEvent.TIMER, timerEvent);
				_timerObj.start();
			}
		

load.phpを無事ロードすることができたら、for each文で読み込んだツイートの数だけテキストフィールドを作成しています。
最後にタイマーをスタートして一定時間ごとに「timerEvent」を実行します。

function timerEvent – Main.as

			function timerEvent(event:Event):void {
				//表示されているツイートを削除
				while(_textContainer.numChildren > 0){
					_textContainer.removeChildAt(0);
				}
				_currentNo++		//現在の番号を次の配列に
				//次のツイートを表示
				_textContainer.addChild(_textArray[_currentNo]);
				//最後の配列にきたら最初に戻る
				if (_currentNo >= _textArray.length) {
					_currentNo = 0;
				} 
			}
		

タイマーイベントによって一定時間ごとに実行されるメソッドです。
表示されていたテキストをremoveして「_currentNo」を一つ進めて次のツイートを表示させています。
最後の配列にきたら新たに読み込んだするとすごくめんどくさそうなので、配列の最初に戻ってループさせています。

これで単純につぶやきを切り替えるスクリプトは完成です。

アニメーションさせる前の準備

アニメーション処理にはTweenerというライブラリを使用します。
下記URLからダウンロードしてください。

Tweener

ファイルを解凍したら「caurina」というフォルダをflaファイルと同一の階層におき、新たにインポートを追加します。

Main.as

		import caurina.transitions.Tweener;
	

これでTweenerを使用する準備ができました。

アニメーションで切り替えるスクリプト

では、ちょっと改良してツイートをアニメーションさせてみましょう。
新たにツイートを移動するメソッド「changeMoveTweet」と、移動した後にツイートをremoveするメソッド「moveComp」を追加します。

Main.as

			/* *****************************************
			ツイートの切り替え処理
			****************************************** */
			function changeMoveTweet(nextNo:uint) {
				_textContainer.addChild(_textArray[nextNo]);
				_textArray[nextNo].y = _panelHeight;
				//Tweener移動処理
				Tweener.addTween(_textArray[nextNo], {
					y:0,
					transition:"liner",
					time:2
				});
				Tweener.addTween(_textArray[_currentNo], {
					y: -_panelHeight,
					transition:"liner",
					time:2,
					onComplete:moveComp,
					onCompleteParams:[_textArray[_currentNo]]
				});
				//次の番号を現在の番号に
				_currentNo = nextNo;
			}
			/* *****************************************
			Tweener移動後
			****************************************** */
			function moveComp(tf:TextField):void{
				//移動後のテキスト削除
				_textContainer.removeChild(tf);
				
			}
		

ほとんどTweenerの説明になりますが、ここでは次のツイートを「panelHeight」文だけ下に配置したら2秒書けてy=0に移動して、同時に現在のツイートは「panelHeight」文だけ上に移動しています。
また、「onComplete」で移動後に実行するメソッドを指定して、「onCompleteParams」にはメソッドの引数を指定できる。

最後に「changeMoveTweet」を実行する為に「timerEvent」を下記に変更しましょう。
以前は直接にremove、addChildを書いていましたが、「changeMoveTweet」メソッドに処理を書きましたので、
タイマーイベントで「changeMoveTweet」を実行するだけですね。

function timerEvent – Main.as

			function timerEvent(event:Event):void {
				if (_currentNo >= (_textArray.length - 1)) {
					changeMoveTweet(0);
				} else {
					changeMoveTweet(_currentNo + 1);
				}
			}
		

なんか余計なことばかりでTwitter的なことはほとんど書いていないきがしますが、一応これで完成です。
あとはハッシュタグを正規表現でリンクとかつけたりとかいろいろ改良する点はありそうです。

最終的なASファイル

Main.as

COMMENTS

hide 2010-08-24 14:54 

はじめまして。
まさに作りたかったものが載っていたので大感謝です。
ただ私はAS3素人で基本的なこともわかっていないと思います。
そこで素人質問で恐縮なのですが・・・
上記の「Main.as」や「function Main–Main.as」「function ioError–Main.as」「function loadComp–Main.as」などの記述部分を上から全部コピーしたものをMain.asとして保存すればいいのでしょうか?それでパプリッシュすると、「public属性はパッケージ内でのみ使用できます」というエラーが3行出てしまいます。
やっていることが全然違うのでしょうか??

hide 2010-08-24 16:26 

上記のhideです。
大変失礼しました。できました!
ご丁寧に入れる場所を書いていただいていたのですね。
理解しました。
FlashでTwiiterの表示を作りたかったので大変重宝しました。
いろいろ調べましたが、ここまで丁寧にスクリプトを書いているページはありませんでした。どうも有り難うございました。

kei_op 2010-08-24 22:42 

hideさん。コメントありがとうございます。
ご自身で解決できたということで良かったです。

masa 2010-08-30 16:55 

はじめまして。
hideさんと同じでまさに作りたかったものなので、大変ありがたいです。

ただ、少々行き詰まっておりまして質問です。

基本的には上記にもどついてやっているのですが、
htmlを開くと「RSSの取得に失敗しました。」エラーが出ます。
load.phpに問題があるのかなと単体で開いてみましたが、
開けたので問題はなさそうです。

Main.asはいじっておりません。
Falshの設定も上記と同じようにしています。
(パブリッシュ時のエラーもないです)

なにか、思い当たる原因ってありますか?

kei_op 2010-08-30 22:24 

masaさん。閲覧ありがとうございます。
サンプルをそのまま実行する場合htmlファイル、load.xmlともに同じフォルダ(同階層)で実行する必要があるのですが、ファイルが別々になっていませんか?
パスを変更する場合、コンストラクタのxmlURLという変数でパスを設定することもできます。

くっきんぐ 2010-09-01 13:38 

こちらでもお世話になります。
くっきんぐです

このかっこいいtwitterなのですが
フォントは変えることができるのでしょうか?

kei_op 2010-09-01 22:26 

フォントを変えのはTextFormatというクラスを使用するとできると思います。
ただダイナミックテキストになりますのであまり選択肢はないですね。
http://livedocs.adobe.com/flash/9.0_jp/ActionScriptLangRefV3/flash/text/TextFormat.html

hide 2010-09-03 16:44 

いつぞやのhideです。お世話になっています。
数日間調べてもうまくいかなかったので、2点、質問させてください。

実は完成後に欲が出て、このFlashに指定したURLに飛ぶように
リンクを設定したいと思って、下記のスクリプトを用意しました。
新しくレイヤーを作ってシンボル→ボタンにしてインスタンス名をbtnにしています。Main.asに記述する方法と、アクション-フレーム欄に記述する方法と、2通り試しましたがエラーが出てしまうのですが、これはどのように解決したらよろしいでしょうか?

btn.addEventListener(MouseEvent.CLICK, buttonClickHandler);
function buttonClickHandler(event:MouseEvent):void{
navigateToURL(new URLRequest(“http://www.指定URL”));
trace(“I’m clicked.”)
}

もう1点は、Twitterのタイムスタンプも表示したいと思ったのですが、これはどのように・・・?

いつも素人質問で申し訳ございません。

kei_op 2010-09-03 22:50 

リンクボタンはとりあえず、その機能だけで動作させることはできてますか?
ぱっと見「””」が全角になっている気がしますが……
時間(?)の方は取得したxmlを見てみるとわかると思うのですが、「created_at」で表示できると思います。

hide 2010-09-04 00:19 

hideです。お返事有難うございます。
ボタンは単独では問題なく動作します。
ただし作成したTwitterFlashですと、フレーム内の方は「スクリプトを記述できない」と表示され、Main.asでは「Main.as、行1 1046 型が見つからないか、コンパイル時定数ではありません : SimpleButton」というエラーが出ます。

kei_op 2010-09-04 23:32 

基本的に外部にスクリプトファイルを置く場合はフレームにはスクリプトは書かない方が良いと思います。
(スクリプトの見通しをよくするために外部しているという意味もありますので)
で、問題のエラーですが「SimpleButton」がインポートされてないんじゃないかと思います。
インポートの所に下記を追加してみてください。
「import flash.display.SimpleButton;」

hide 2010-09-05 01:26 

お返事有難うございます。
インポートで「import flash.display.SimpleButton;」を追加しました。

すると今度は下記のエラーが。
「未定義である可能性のあるメソッド addEventListener を、静的型 Class の参照を使用して呼び出しました。」

書いたところは、public function Main(){ } の中ですが
書く場所はここでいいのでしょうか?

hide 2010-09-05 14:50 

hideです。自己解決しました。
いろいろご面倒をおかけしてすみませんでした。

インポートに下記を追加して、いろいろやってみたら出来ました。

import fl.motion.Motion;
import flash.display.SimpleButton;
import flash.events.MouseEvent;
import flash.net.navigateToURL;

hide 2010-09-05 17:55 

hideです。
最後にTwitter投稿時刻の表示なのですが、上記でおっしゃっている、「created_atで表示できると思います。」とはXMLのの部分のことだと思います。のツイート部分の読み込みと同じようにすれば表示するのだと思うのですが、どこをどうすれば良いのかわかりません。しつこくて、申し訳ございません。

kei_op 2010-09-05 22:14 

サンプルを例にしますと、82行目のfor eachでXMLの情報を配列に入れてるんですね。
2つ以上値を表示する場合はforの「rss.status.text」の部分を「rss.status」に、84行目の「item」を「item.text」にします。
時間を取得するにはこの「text」という部分を「created_at」にすればできます。

hide 2010-09-06 14:20 

hideです、お世話になっています。
82行目以降を下記のようにしてみましたが、エラーにはならないものの、表示はできませんでした。根本的に間違いですかね?

for each(var item:Object in rss.status) {
_textArray.push(new TextField());
_textArray[count].text = item.text;
_textArray[count].created_at = item.created_at;

kei_op 2010-09-06 22:03 

textArrayのtextというのはTextFieldのプロパティですのでtextにしないとテキストを入れることができません。
あとこれだと配列に上書きされているので時間用の配列を一つ作る必要があります。

hide 2010-09-07 04:25 

hideです。お返事有難うございます。
時間用の配列ですか・・・ちょっと私には無理のようです。
残念ですがあきらめます。
お忙しいのにお付き合いいただき、どうも有難うございました。

Marine 2011-04-25 20:32 

はじめまして。
お忙しいところ申し訳ありませんが、
2,3不明な点がありましてご質問します。

2010年にtwitterの仕様変更がありましたが、
現在の仕様でも動作可能でしょうか?

ドキュメントクラスの設定は
パブリッシュ設定の中だけで良いのでしょうか?
テキストエリアの設定等は不要でしょうか?

Kenkichi 2011-04-25 22:27 

>Marineさん
サンプルのリンク外れてましたね。再度リンクして確認してみたら動いていたので、今でも使えるはずです。

ドキュメントクラスの設定は下記を参考にしていただければと思います。
http://www.webopixel.net/actionscript/120.html

テキストエリアはASで配置しているのでFlash側で配置する必要はなかったはずです。

Marine 2011-04-26 15:21 

ありがとうございます。

サーバーの仕様なのか
phpからのxml出力がうまく行ってなかったようで
こちらのコードと合わせて出力されたxmlを読む形にしたら、
うまくいきました^^
http://yorozu-1.com/index.php?MEMO/twitter/1
色々と手があるものなのですね。

デザインに幅が広がる気がしまして、
基本的なところをもう一つだけご意見いただきたいのですが、
AS3で生成されたこのSWFを、切り替えボタンなどを用いず、
別のflashコンテンツに、外部SWFとして、
親ページの表示と一緒に読み込ませるには、
どういった方法がありましょうか?

Kenkichi 2011-04-26 21:37 

単純に外部swfを読み込むだけならばLoaderクラスを使用すればできると思います。
ただ、このswfですとすでに外部xmlを読み込んでいるのでいるので、うまく動作するかはわかりません。
最近ちょっとFlashから離れてしまってまして、詳しく答えられなくてすみません。

くっきんぐ 2012-12-02 13:53 

お世話になります。

こちらのFlashですがtwitter仕様改訂により動作しなくなっていると思われます。

xmlのパス変更だけではダメなのでしょうか

webOpixel 2012-12-04 14:17 

取得するURLに関しては下記を参考にしてください。
http://www.webopixel.net/javascript/650.html

たぶん構造は変わっていないと思うのですが、もし変わってたら、
「function loadComp」の「rss.status.text」あたりを修正すれば大丈夫なんじゃないかなと思います。

最近はFlashから離れていることもあり、サンプルの修正はできないかもしれません、すみません。

LEAVE A REPLY

コードを書く場合は<pre>で囲んでください。