AIR/Flex: 2009年2月アーカイブ

今回は、簡単なスライドショーガジェットを作ってみた。
3枚の画像を10秒毎に切り替えて表示という処理を延々繰り返す。
この間作った電光掲示板もどきより制御も簡単で、特に目新しいもの無し。

一点。
タイマーイベントの一発目の処理は、指定しているインターバルタイムが最初に経過した後なので、タイマーイベントを開始する前に、一発目の処理を実行しておく必要あり。
今回の場合であれば、1枚目の絵のパスセット。
こうしないと、最初の 10秒間は何も表示していない状態になってしまう。


<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="absolute"
    width="340" height="100" color="#0B333C"
    initialize="initProc();">
    <mx:Image x="0" y="0" width="340" height="100" id="img1"/>

    <mx:Script>

        <![CDATA[

            public var FilePath:Array    = new Array();    // 画像パス
            public var FileIndex:int;    // 配列インデックス

            //============================
            // メイン処理(10秒毎に画像パスセット処理呼び出し)
            //============================
            private function initProc():void {

                setFilePath();

                FileIndex    = 0;    // 最初の画像
                img1.source    = FilePath[FileIndex];    // 最初のパスセット

                var timeProc1:Timer = new Timer(10000);    // 10秒毎
                timeProc1.addEventListener(TimerEvent.TIMER, setImage);
                timeProc1.start();

            }

            //============================
            // メイン処理(10秒毎に画像パスセット処理呼び出し)
            //============================
            private function setImage(event:TimerEvent):void {

                FileIndex++;

                if (FileIndex >= FilePath.length) {
                    FileIndex    = 0;
                }

                img1.source    = FilePath[FileIndex];    // パスのセット

            }

            //============================
            // 表示画像のパス設定
            //============================
            private function setFilePath():void {

                FilePath[0]
                    = "file:///M|/X/data/TEST/src/img/carp.jpg";
                FilePath[1]
                    = "file:///M|/X/data/TEST/src/img/iwakuni.jpg";
                FilePath[2]
                    = "file:///M|/X/data/TEST/src/img/metro.jpg";

            }

        ]]>
    </mx:Script>

</mx:WindowedApplication>


うーん・・・どうでもいいが、ファイルパスの相対パス設定の仕方がわからん。
ああ、これ、URL だな。
ローカルの画像ファイルを「ファイルパス」で指定して読み込んで表示するには、別のやり方をしないといけないということか。

しつこく文字列横スクロールの話。

前回までは1つの文字列を一度スクロールさせたら終わりだったが、今回は複数の文字列(配列にセット)を順番に延々とスクロールさせ続けるプログラム。

一回で終わりなら timerComplete イベントで終了処理(文字列が左端に消えていく処理)を行えばいいのだが、複数の文字列の表示を順に延々行うケースで timerComplete イベントは使えない。だって、「延々処理を繰り返す」ので TIMER_COMPLETE な状態にはならないもん。

ということで、グローバル変数でスクロール処理回数を保持し、それと文字列の表示枠の大きさとを比較して処理の終了タイミングを見たり、次の文字列に移ったとき、スクロール処理回数を初期化(0回)したりといった「泥臭い」処理を組み込んでやる。これが一番簡単。下手に複数の Timer イベントを駆使して実現しようとすると地獄を見るし、技術者的には楽しいかもしれんけど、そんなソースを後で見せられてもメンテナンスできんで。(笑)

ということで、以下がサンプル。


<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication
    xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="absolute"
    initialize="initProc();" width="367" height="109">

    <mx:Script>
        <![CDATA[

            // グローバル変数
            public var TextIndex:int;    // 処理中の文字列配列添字
            public var ProcCount:int;    // 処理の実行回数

            public var TextData:Array    = new Array();    // 表示文字列
            public var TextLastData:Array    = new Array();    // 消えていく文字列処理用

            // 定数
            // text1 に表示できる最大文字数
            public static const MAX_TEXT_SIZE:int    = 40;

            //================================================================
            // 初期処理(メイン)
            //================================================================
            private function initProc():void {

                setText();    // 表示文字列を配列にセット

                TextIndex    = 0;    // 最初の配列
                ProcCount    = 0;    // 文字列セット処理回数 0回

                // ひたすら表示文字列セット処理を呼び続ける
                var timeCheck1:Timer = new Timer(100);    // 100ミリ秒毎
                timeCheck1.addEventListener(TimerEvent.TIMER, setText2Label);
                timeCheck1.start();

            }

            //================================================================
            // ラベルへの表示文字列セット処理
            //================================================================
            private function setText2Label(event:TimerEvent):void {

                ProcCount++;

                if (ProcCount <= 1) {    // 初回のみ
                        TextLastData[TextIndex]    = TextData[TextIndex];
                }

                // まだ、処理回数が文字列の長さを超えてない?
                // (ちなみに、文字列が左端まで行ったところで 2秒ほど動きを
                // 停止させたいので MAX_TEXT_SIZE に +20している)
                if (ProcCount <= (MAX_TEXT_SIZE + 20)) {

                    // 時間が経過する毎に、表示文字列の前に挿入する全角スペー
                    // スの数を減らしていく
                    var blankCnt:int    = MAX_TEXT_SIZE - ProcCount;
                    if (blankCnt <= 0) {
                        label1.text    = TextData[TextIndex];
                    }
                    else {
                        label1.text    = (new Array(blankCnt).join(" ")) + TextData[TextIndex];
                    }

                }
                else {

                    // 時間が経過する毎に、表示文字列の一番前の文字を削除
                    // (文字列がだんだん消えていく動き)
                    TextLastData[TextIndex]    = TextLastData[TextIndex].substr(2);
                    label1.text    = TextLastData[TextIndex];

                    // 最後に、次の文字列処理を許可する
                    if (TextLastData[TextIndex] == '') {
                        TextIndex++;
                        ProcCount    = 0;    // 処理回数初期化

                        // 配列の最後までいったら最初に戻る
                        if (TextIndex >= TextData.length) {
                            TextIndex    = 0;
                        }

                    }

                }

            }

            //================================================================
            // 表示文字列の設定
            //================================================================
            private function setText():void {

                TextData[0]    = "わたしは宇宙からきたゴリ星人だ。";
                TextData[1]    = "あなたは衣笠似のゴリラだ。";
                TextData[2]    = "あなたはゴリラ似のガッツ石松だったのですね?";

            }

        ]]>
    </mx:Script>
    <mx:Label x="41" y="24" text="この下に文字が流れながら表示されます"/>
    <mx:Label x="41" y="50" width="279" id="label1"/>

</mx:WindowedApplication>


ちなみに、TextIndex が 0 のときに setText 処理を呼ぶようにすれば、TextLastData を使わずに直接 TextData を使えばいいので、グローバル変数も減るし、TextData の値を TextLastData にセットする処理も減るので幾分ソースもスッキリすると思うが、そこは、まあ、好き好きで。

AS_test4_2.gif

この間書いた「文字列が横スクロールする AIR アプリ」の続き。

この間は、右から現れた文字列が左端までスクロールしてくるところまで作った。今回は、Label の左端までスクロールして一旦停止後、今度はそのまま左側にスクロールしながら消えていく動きを追加。

左端までスクロールさせる timer イベントが終了した時に実行される timerComplete イベントで「その後、文字が更に左にスクロールして消えていく」処理を呼び出します。

「その後、文字が更に左にスクロールして消えていく」処理の中では、また別の timer イベントを発生させ、文字列が空になるまで処理繰り返します。
文字列が空になるまで処理を繰り返すのは、「左スクロール」の動きを、文字列の一文字目の文字を削除しては表示を繰り返すことで実現しているからじゃね。


<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication
 xmlns:mx="http://www.adobe.com/2006/mxml"
 layout="absolute"
 initialize="initProc();" width="367" height="109">

 <mx:Script>
  <![CDATA[

   // グローバル変数
   public var TextData:String = "わたしは宇宙からきたゴリ星人だ。多分、そうだ。"; // 表示文字列
   // 定数
   public static const MAX_TEXT_SIZE:int = 40; // text1 に表示できる最大文字数

   private function initProc():void {

    var timeCheck:Timer = new Timer(100, MAX_TEXT_SIZE + 10);
    timeCheck.addEventListener(TimerEvent.TIMER, onTick);
    timeCheck.addEventListener(TimerEvent.TIMER_COMPLETE, onTimerComplete);  // 左端まで移動した後の処理
    timeCheck.start();

   }

   // ラベルにセットする文字列の編集
   private function onTick(event:TimerEvent):void {

    // 時間が経過する毎に、表示文字列の前に挿入する全角スペースの数を減らしていく
    var blankCnt:int = MAX_TEXT_SIZE - event.target.currentCount;
    
    if (blankCnt <= 0) {
     label1.text = TextData;
    }
    else {
     label1.text = (new Array(blankCnt).join(" ")) + TextData;
    }

   }

   private function onTimerComplete(event:TimerEvent):void {

    // 文字列の文字数分だけ処理を行う
    var timeCheck2:Timer = new Timer(100, TextData.length);
    timeCheck2.addEventListener(TimerEvent.TIMER, onTick2);
    timeCheck2.start();

   }

   // ラベルにセットする文字列の編集
   private function onTick2(event:TimerEvent):void {

    // 時間が経過する毎に、表示文字列の一番前の文字を削除
    TextData = TextData.substr(2);
    // ラベルにセット
    label1.text = TextData;

   }

  ]]>
 </mx:Script>
 <mx:Label x="41" y="24" text="この下に文字が流れながら表示されます"/>
 <mx:Label x="41" y="50" width="279" id="label1"/>

</mx:WindowedApplication>


こんな感じ。