ケータイFlashで階層型メニューを作ってみよう

By ookura - 09/03/04 - このエントリをはてなブックマークに追加このエントリをYahoo!ブックマークに追加このエントリをdel.icio.usに追加このエントリをFC2ブックマークに追加

今回は階層型のメニュー制作について説明します。
※今回のサンプルはFlashLite1.1対応です。
 
スクロールの方法は以前紹介させていただいた以下のサンプルを参考にして下さい。
参照:ケータイFlashで縦スクロールするページを作ってみよう(3ボタン制御編)
 

画面イメージ


 
 

サンプルページ


URLをメールで送る
http://ookura.tanikaze.com/Sample/post2703/
 
 

flaファイルサンプル

sample2703.zip※Flash8形式
 
 

階層型インタフェースのメリット

縦スクロールのメニューインタフェースの場合、メニューが多くなってくると1画面に表示する項目が多くなり、目的のメニューにたどり着くまでに時間がかかってしまいます。
 
そこで、メニューをメインメニューとサブメニューの2階層に分けて、メインメニューの項目をクリックするとサブメニューが表示され、サブメニューを閉じるとメインメニューが選択できるようにするとコンテンツが多くても目的のメニューにスムーズにアクセスできます。
 
メニューの開閉は左右キーで行うイメージがありますが、左右が使用できるのは一部機種のみなので、ここでは汎用的に使えるように上下キーと決定キーのみでアクセスできるようにしました。
 
HTMLのページであればページ内リンクやページ遷移が必要になりますが、Flashで作成する場合は画面遷移なしで作成できます。
 
 

手順1:メインメニューの作成

swfファイルの作り方を説明していきます。
 
まず240×240pxでFlashLiteのバージョンを1.1にします。
 
次にレイヤーを4つ追加します。
上から順に、label,action,button,window,mainとします。
 
次にフレームを5フレーム目まで広げます。
 
labelレイヤーは2フレーム目、3フレーム目、4フレーム目にキーフレームを追加します。
フレームラベルをそれぞれ以下のように設定します。
2フレーム目:select
3フレーム目:press
4フレーム目:scroll
 
actionレイヤーは全てキーフレームにします。
[図94]
 
次にシェイプでボタンを作成し、3つにコピーして上から順に配置します。
ボタンはbuttonレイヤーに配置します。
[図95]
 
mainレイヤーに背景を作成します。240×600pxのグラデーションシェイプを作成し、x:0,y;0の位置に配置します。
グラフィックシンボル(main_back)にしてからさらにムービークリップ(main_mc)に変換します。
インスタンス名は「main」とします。
[図96]
 
ムービークリップ「main_mc」の中に入り、レイヤーを3つ追加します。
上から順に、cursor,text,logo,backとします。
背景のグラフィックはbackレイヤーに配置し、Y座標-60の位置に移動します。
 
logoレイヤーにロゴを作成します。ここでは適当なグラデーションシェイプ(logo_back)とテキストを配置しました。
テキストは静止テキストで適当につけています。
[図97]
ロゴ画像を別に作成して読み込むのも一つの方法かと思います。
 
textレイヤーにダイナミックテキストを9個配置していきます。
今回は12ptの白色等幅フォントで220pxの単一行テキストをx:20,y;130の位置から順に30px間隔で配置しました。
各ダイナミックテキストのプロパティの「変数」の項目に上から順に「menu_1」,「menu_2」…と変数名を指定していきます。
一番下にコピーライトテキストも静止テキストとして配置しました。
[図98]
 
cursorレイヤーに多角形ツールで三角形のシェイプを配置し、ムービークリップ(main_cursor)に変換します。
インスタンス名を「main_cursor」としておき、一番上のダイナミックテキストの右側の画面外に配置しておきます。
 
 

手順2:サブメニューの作成

シーン1に戻り、windowレイヤーにサブウィンドウを作成していきます。
 
windowレイヤーに矩形ツールで160×160pxの四角いシェイプを作成します。ふちは2pxの白線にしておきます。
[図99]
シェイプをムービークリップ(win_mc)にしてインスタンス名を「win」とします。
そのままwin_mcの中に入ります。
 
今回のサンプルでははサブウィンドウのふちを丸く加工します。
デザイン上の問題ですのでこの工程は特にスルーしても問題ありません。
表示→グリッド→グリッドの表示でグリッド表示をONにします。
表示→グリッド→グリッドの編集でグリッド幅を20px×20pxとし、グリッドに吸着を有効にします。
楕円ツールで4隅に塗りなしの円を作成します。
[図100]
不要な線や塗りを削除すると丸いふちの四角形ができ上がります。
[図101]
 
win_mcムービークリップに4つのレイヤーを追加します。
上から順に、action,cursor,text,back,shadowとします。
先ほど作成したシェイプはbackレイヤーに配置します。
 
今回のサンプルではメインメニューの番号によってサブウィンドウの背景色を変更します。
フレームを9フレーム目まで広げます。
actionレイヤーは全てキーフレームにし、全てのフレームに以下のように記述します。

stop();

backレイヤーも全てキーフレームに変換します。
2フレーム目から9フレーム目までの背景色を適当な色に変更します。
[図102]
 
shadowレイヤーには半透明な影を配置します。
backレイヤーの塗りをコピーしてbackレイヤーを非表示にし、shadowレイヤーに同じ位置にペーストします。
白く塗りつぶしてグラフィックシンボル(window_shadow)に変換します。
プロパティ→カラーでアルファを選択し、30%に設定します。
位置を右下に5px移動させて影として見えるように調整します。
調整できたら非表示にしていたbackレイヤーを表示に変更します。
[図103]
 
textレイヤーにはウィンドウのタイトルと5つのメニューをダイナミックテキストで配置します。
12ptの白色等幅フォントでタイトルは中央揃え、メニューは左揃えにします。
タイトルは変数名を「menu_ttl」としておきます。
各メニューは変数名を上から順に「menu_1」~「menu_5」と設定します。
一番下に静止テキストで「閉じる」メニューをつけます。
[図104]
 
cursorレイヤーには多角形ツールで三角形のシェイプを配置し、ムービークリップ(sub_cursor)にしておきます。
インスタンス名は「sub_cursor」とします。
ウィンドウ外の右側の少し離れた場所に移動しておきます。
[図105]
 
ここまでできたら、win_mcムービークリップから出てシーンに戻ります。
ここまででパーツの配置は完了です。
 
 

手順3:ボタンアクションの記述

次にアクションを記述します。
 
それぞれのボタンにアクションを設定していきます。
1番目のボタン
[図106]

on (rollOver) {
    currentBtn = 1;
    pressKey = "";
    call("select");
}
on (press,keyPress "<Enter>") {
    pressKey = "";
    call("press");
}
on (keyPress "1") {
    pressKey = "1";
    call("select");
}
on (keyPress "2") {
    pressKey = "2";
    call("select");
}
on (keyPress "3") {
    pressKey = "3";
    call("select");
}
on (keyPress "4") {
    pressKey = "4";
    call("select");
}
on (keyPress "5") {
    pressKey = "5";
    call("select");
}
on (keyPress "6") {
    pressKey = "6";
    call("select");
}
on (keyPress "7") {
    pressKey = "7";
    call("select");
}
on (keyPress "8") {
    pressKey = "8";
    call("select");
}
on (keyPress "9") {
    pressKey = "9";
    call("select");
}
on (keyPress "#") {
    pressKey = "#";
    call("press");
}

 
ロールオーバーイベントとpressイベントの他に、1~9までと#キーのkeyPressイベントを記述します。
 
press系のイベントはどれかのボタンに記述すれば有効になります。
なので2番目のボタン以降はロールオーバーイベントのみ記述します。
 
2番目のボタン

on (rollOver) {
    currentBtn = 2;
    pressKey = "";
    call("select");
}

 
3番目のボタン

on (rollOver) {
    currentBtn = 3;
    pressKey = "";
    call("select");
}

 
以前のサンプルでボタンアクションに記述していたいくつかのアクションはselectラベルにまとめて記述するようにしましたので、かなり簡潔になりました。
 
 

手順4:フレームアクションの記述

次にフレームアクションやcall関数で呼び出されるアクションをフレームに記述していきます。
 
1フレーム目
最初だけ実行されるアクションになります。
[図107]

// 初期アクション
// フォーカス枠を表示しない
_focusrect = false;
// レンダリング画質を「高」にする
fscommand2("SetQuality", "high");
// 最初は未選択なので初期ボタン番号は0
btnNo = 0;
// 選択番号は1とする
mainSelectNo = 0;
subSelectNo = 0;
// サブウィンドウの初期値は0
subWindow = 0;
// メインメニューの最大値は9
main_menu_max = 9;
// サブメニューの最大値はメニュー5件+CLOSE1件で6
sub_menu_max = 6;
// メインメニューの文字列指定
menu_1 = '1.メインメニュー1';
menu_2 = '2.メインメニュー2';
menu_3 = '3.メインメニュー3';
menu_4 = '4.メインメニュー4';
menu_5 = '5.メインメニュー5';
menu_6 = '6.メインメニュー6';
menu_7 = '7.メインメニュー7';
menu_8 = '8.メインメニュー8';
menu_9 = '9.メインメニュー9';
// サブメニューの文字列指定
menu_1_1 = '1) リンク1';
menu_1_2 = '2) リンク2';
menu_2_1 = '1) リンク1';
menu_3_1 = '1) リンク1';
menu_3_2 = '2) リンク2';
menu_3_3 = '3) リンク3';
menu_3_4 = '4) リンク4';
menu_3_5 = '5) リンク5';
menu_4_1 = '1) リンク1';
menu_4_2 = '2) リンク2';
menu_4_3 = '3) リンク3';
menu_4_4 = '4) リンク4';
menu_5_1 = '1) リンク1';
menu_5_2 = '2) リンク2';
menu_5_3 = '3) リンク3';
menu_6_1 = '1) リンク1';
menu_6_2 = '2) リンク2';
menu_6_3 = '3) リンク3';
menu_7_1 = '1) リンク1';
menu_7_2 = '2) リンク2';
menu_7_3 = '3) リンク3';
menu_8_1 = '1) リンク1';
menu_8_2 = '2) リンク2';
menu_8_3 = '3) リンク3';
menu_9_1 = '1) リンク1';
menu_9_2 = '2) リンク2';
menu_9_3 = '3) リンク3';
// サブメニューのリンク先指定
link_1_1 = '/Sample/post2703/link/menu/1/sub/1/';
link_1_2 = '/Sample/post2703/link/menu/1/sub/2/';
link_2_1 = '/Sample/post2703/link/menu/2/sub/1/';
link_3_1 = '/Sample/post2703/link/menu/3/sub/1/';
link_3_2 = '/Sample/post2703/link/menu/3/sub/2/';
link_3_3 = '/Sample/post2703/link/menu/3/sub/3/';
link_3_4 = '/Sample/post2703/link/menu/3/sub/4/';
link_3_5 = '/Sample/post2703/link/menu/3/sub/5/';
link_4_1 = '/Sample/post2703/link/menu/4/sub/1/';
link_4_2 = '/Sample/post2703/link/menu/4/sub/2/';
link_4_3 = '/Sample/post2703/link/menu/4/sub/3/';
link_4_4 = '/Sample/post2703/link/menu/4/sub/4/';
link_5_1 = '/Sample/post2703/link/menu/5/sub/1/';
link_5_2 = '/Sample/post2703/link/menu/5/sub/2/';
link_5_3 = '/Sample/post2703/link/menu/5/sub/3/';
link_6_1 = '/Sample/post2703/link/menu/6/sub/1/';
link_6_2 = '/Sample/post2703/link/menu/6/sub/2/';
link_6_3 = '/Sample/post2703/link/menu/6/sub/3/';
link_7_1 = '/Sample/post2703/link/menu/7/sub/1/';
link_7_2 = '/Sample/post2703/link/menu/7/sub/2/';
link_7_3 = '/Sample/post2703/link/menu/7/sub/3/';
link_8_1 = '/Sample/post2703/link/menu/8/sub/1/';
link_8_2 = '/Sample/post2703/link/menu/8/sub/2/';
link_8_3 = '/Sample/post2703/link/menu/8/sub/3/';
link_9_1 = '/Sample/post2703/link/menu/9/sub/1/';
link_9_2 = '/Sample/post2703/link/menu/9/sub/2/';
link_9_3 = '/Sample/post2703/link/menu/9/sub/3/';
// 各ウィンドウのタイトルにはメインメニューのタイトルを設定
for (i=1; i<=main_menu_max; i++) {
    eval("/main/:menu_" add i) = eval("menu_" add i);
}
// サブウィンドウの初期位置・アルファを指定
tellTarget ("win") {
    targetX = 320;
    targetY = 80;
    targetAlpha = 0;
}
stop();

 
初期設定と初期値を指定し、各メニューの文字列やリンク先を設定しています。
そしてメインメニューの文字列とサブウィンドウの位置やアルファの初期値を設定しています。
最後はstop();で次のフレームのアクションを実行しないようにします。
 
2フレーム目
メニュー選択時の処理を記述します。
[図108]

// ロールオーバーしたときのアクション
// テンキーでのアクションでない場合のみ
if (pressKey eq "") {
    // 1番目のボタンにフォーカスしている場合
    if (currentBtn == 1) {
        if (btnNo == 2) {
            btnDir = "up";
        } else {
            btnDir = "down";
        }
        // 2番目のボタンにフォーカスしている場合
    } else if (currentBtn == 2) {
        if (btnNo == 3) {
            btnDir = "up";
        } else {
            btnDir = "down";
        }
        // 3番目のボタンにフォーカスしている場合
    } else if (currentBtn == 3) {
        if (btnNo == 0) {
            btnDir = "up";
        } else if (btnNo == 1) {
            btnDir = "up";
        } else {
            btnDir = "down";
        }
    }
}
// サブウィンドウを閉じている時     
if (subWindow == 0) {
    // テンキーでのアクションでない場合
    if (pressKey eq "") {
        // ボタンの上下移動を元にスクロール番号を増減 
        if (btnDir eq "up") {
            mainSelectNo--;
        }
        if (btnDir eq "down") {
            mainSelectNo++;
        }
        // スクロール番号が端まで達したら反対側にループさせる        
        if (mainSelectNo<1) {
            mainSelectNo = main_menu_max;
        } else if (mainSelectNo>main_menu_max) {
            mainSelectNo = 1;
        }
    // テンキーを使用している場合
    } else {
        // テンキーの数字を選択メニュー番号とする
        mainSelectNo = int(pressKey);
    }
    // メインステージのスクロール座標 
    tellTarget ("main") {
        // 3メニュー毎に変化させる
        targetY = ((int((eval("/:mainSelectNo")-1)/3))*-90);
    }
    // メインカーソルのスクロール座標
    tellTarget ("main/main_cursor") {
        _x = 5;
        targetY = ((eval("/:mainSelectNo")+1)*30)+70;
    }
    // スクロール処理をループ実行する
    gotoAndPlay("scroll");
    // サブウィンドウを開いている時
} else {
// テンキーでのアクションでない場合
    if (pressKey eq "") {
        // ボタンの上下移動を元にスクロール番号を増減 
        if (btnDir eq "up") {
            subSelectNo--;
            // サブメニュー文字列が空の場合はスルー
            while (eval("win/:menu_" add subSelectNo) == "") {
                // 最初のメニューに達したらスルー終了
                if (subSelectNo<1) {
                    break;
                }
                subSelectNo--;
            }
        }
        if (btnDir eq "down") {
            subSelectNo++;
            // サブメニュー文字列が空の場合はスルー
            while (eval("win/:menu_" add subSelectNo) == "") {
                // 閉じるメニューに達したらスルー終了
                if (subSelectNo>(sub_menu_max-1)) {
                    break;
                }
                subSelectNo++;
            }
        }
        // スクロール番号はループさせる        
        if (subSelectNo<1) {
            subSelectNo = sub_menu_max;
        } else if (subSelectNo>sub_menu_max) {
            subSelectNo = 1;
        }
    // テンキーを使用している場合
    } else {
        // メニューの文字列が設定されている場合は
        if (eval("win/:menu_" add pressKey) ne "") {
            // テンキーの数字を選択メニュー番号とする
            subSelectNo = int(pressKey);
        }
    }
    if ((pressKey eq "") || (eval("win/:menu_" add pressKey) ne "")) {
        // サブウィンドウのカーソル座標を指定  
        tellTarget ("win/sub_cursor") {
            if (/:subSelectNo == /:sub_menu_max) {
                _x = 48;
                _y = 129;
            } else {
                _x = 10;
                _y = eval("/:subSelectNo")*18.6+15;
            }
        }
    }
}
// ボタン番号を更新する
btnNo = currentBtn;

 
前回のサンプルでボタンアクションに記述していたロールオーバー時のアクションをこちらに持ってきています。
 
フォーカス方向またはキーを取得し、メニュー番号を決定します。
 
サブウィンドウの開閉状態を確認して制御するウィンドウを判断します。
 
メニュー番号を元にウィンドウとカーソルの位置を計算し、スクロールが必要な場合はscrollフレームに移動します。
 
最後に現在のボタン番号を更新します。
 
call関数からの呼び出しのため、最後はstop();を記述しません。
 
 
3フレーム目
決定キーや「#」を押した時のアクションを記述します。
ウィンドウやカーソルの目標座標の変更や、ウィンドウメニューの文字列の変更を行います。
ウィンドウの背景変更はウィンドウのフレームを指定することで実現しています。
最後はスクロールを実行します。
サブメニューが選択されている状態の場合はgetURL関数でリンク先に遷移します。
[図109]

// ボタンを押したときのアクション
// サブウィンドウを閉じているとき
if (subWindow == 0) {
    // テンキーを使用していない&メインメニューが選択されている時
    if ((pressKey eq "") && (mainSelectNo != 0)) {
        // サブウィンドウは1とする
        subWindow = 1;
        // サブウィンドウの表示座標を指定
        tellTarget ("win") {
            targetX = 40;
            targetY = 80;
            targetAlpha = 85;
        }
        // サブウィンドウのメニュータイトルを更新
        win/:menu_ttl = eval("/:menu_" add mainSelectNo);
        // サブメニューを更新
        for (i=1; i<sub_menu_max; i++) {
            eval("win/:menu_" add i) = eval("/:menu_" add mainSelectNo add "_" add i);
        }
        // 背景をメニュー番号に合わせて変更
        tellTarget ("win") {
            gotoAndStop(/:mainSelectNo);
        }
        // スクロールを実行
        gotoAndPlay("scroll");
    }
    // サブウィンドウを開いているとき 
} else {
    // 閉じるを選択している場合
    if ((subSelectNo == sub_menu_max) || (pressKey eq "#")) {
        // サブウィンドウは0とする
        subWindow = 0;
        // サブメニュー番号を初期化
        subSelectNo = 0;
        // サブウィンドウの格納座標を指定
        tellTarget ("win") {
            targetX = 320;
            targetY = 80;
            targetAlpha = 0;
        }
        // カーソル座標を初期化
        tellTarget ("win/sub_cursor") {
            _x = 240;
            _y = 0;
        }
        // スクロールを実行
        gotoAndPlay("move");
    // 閉じる以外のメニューを選択している場合
    } else {
        // サブメニューを選択している場合
        if ((subSelectNo>0) && (subSelectNo<sub_menu_max)) {
            // 指定URLにリンク
            getURL(eval("link_" add mainSelectNo add "_" add subSelectNo));
        }
    }
}

 
4フレーム目
scrollラベルのアクションを繰り返し実行してウィンドウやカーソルをだんだんと目標座標に移動させます。
[図112]

// ループしてスクロールを制御
// メインウィンドウのスクロール
tellTarget ("main") {
    _y += (targetY-_y)/2;
}
// メインカーソルのスクロール
tellTarget ("main/main_cursor") {
    _y += (targetY-_y)/1.2;
}
// サブウィンドウのスクロール
tellTarget ("win") {
    _x += (targetX-_x)/2;
    _y += (targetY-_y)/2;
    _alpha += (targetAlpha-_alpha)/2;
}

 
5フレーム目
[図110]
繰り返し実行するためにscrollラベルに戻ります。

// scrollフレームに戻ってループ
gotoAndPlay("scroll");

 
ここまで完了したら、パブリッシュしてサーバーにアップロードします。
[図111]
 
 

備考

階層型メニューはアイデア次第でいろいろと応用できます。
 
本サンプルは一例として参考にしていただければと思います。