プラグイン集

無料ブログはココログ
2022年1月
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          

サンプルJS

  • ユーロバカ一代の締切
    ・・・初期化中・・・

« 天気図作成ソフト3種を比較する | トップページ | 図書館総合展2014(第16回) »

2014年10月25日 (土)

Androidのオプションメニューを動的に変える方法

Androidでプログラムを組んでいて、オプションメニューのサブメニューを変えたいと思った。
この前のふらんちゃんと出かけられるアプリ を改造して、レミリアお嬢様と咲夜さん連れだせるようにしようと改造を決意。表情の数とファイル番号のパターンが、フランちゃん共通ではない。なので、サブメニューのキャプションを変えてあげないと、何が選択されるか分からない。

先に行っておくと、Androidの元締めであるGoogleは、メニューの変更は、ユーザーに混乱をもたらすので、するべきではないとしている。
しかしながら、オプションのボタンの表示と実際の表示が異なる方が、問題だと自分は思うので、Googleの意図に反して、実装を決めた。※Googleは、こういう事態がにならないよう設計を見直すように薦めている。

早い段階で、動的にオプションメニューを変えるには、Activityクラスを継承したクラスで、onPrepareOptionsMenuというメソッドをオーバーライドして使えばいいと分かった。
だか、ここからが難航する。これは、実際にコードを見てもらった方が速いだろう。

//最初にメニューを作るところ
@Override
public boolean onCreateOptionsMenu(Menu menu) {
	// Inflate the menu; this adds items to the action bar if it is present.
	//getMenuInflater().inflate(R.menu.activity_flan_gps, menu);
	//メニュー
	menu.add(Menu.NONE,MENU_ID_0,Menu.NONE,"保存");
	//キャラクターの表情を入れ替えるためのサブメニュー
	SubMenu subMenu;
	subMenu=menu.addSubMenu(Menu.NONE,MENU_ID_3,Menu.NONE,"表情");
	//flandre_menu
	subMenu.add(GM_ID0,SUB_MENU_ID0 , Menu.NONE, "通常");
	subMenu.add(GM_ID0,SUB_MENU_ID1 , Menu.NONE, "目閉じ");
        //~中省略~

	//remilia_menu
	subMenu.add(GM_ID1,SUB_MENU_ID0 , Menu.NONE, "通常");
	subMenu.add(GM_ID1,SUB_MENU_ID1 , Menu.NONE, "口閉じ");
	subMenu.add(GM_ID1,SUB_MENU_ID2 , Menu.NONE, "驚き");
        //~中省略~

	//sakuya_menu
	subMenu.add(GM_ID2,SUB_MENU_ID0 , Menu.NONE, "通常");
	subMenu.add(GM_ID2,SUB_MENU_ID1 , Menu.NONE, "おやっ");
	subMenu.add(GM_ID2,SUB_MENU_ID2 , Menu.NONE, "あらあら");
        //~中省略~

	SubMenu subMenu2;//別のサブメニュー
	subMenu2=menu.addSubMenu(Menu.NONE, MENU_ID_4, Menu.NONE, "キャラ");
	subMenu2.add(Menu.NONE,SUB_MENU2_ID0,Menu.NONE,"フラン");

        //Android3系から、初回に onPrepareOptionsMenuが呼ばれなくなるので、
	//メニューを最初から選択しておく
	switch (main_char) {
	case 0:
		//flandre
		subMenu.setGroupVisible(GM_ID0, true);
		subMenu.setGroupVisible(GM_ID1, false);
		subMenu.setGroupVisible(GM_ID2, false);
		break;
	case 1:
		//remilia
		subMenu.setGroupVisible(GM_ID0, false);
		subMenu.setGroupVisible(GM_ID1, true);
		subMenu.setGroupVisible(GM_ID2, false);
		break;
	case 2:
		//sakuya
		subMenu.setGroupVisible(GM_ID0, false);
		subMenu.setGroupVisible(GM_ID1, false);
		subMenu.setGroupVisible(GM_ID2, true);
		break;
	case 3:
		break;
	default:
		//メニューが範囲外起こして、デフォルトになるようなら、元のフランに戻す
		subMenu.setGroupVisible(GM_ID0, true);
		subMenu.setGroupVisible(GM_ID1, false);
		subMenu.setGroupVisible(GM_ID2, false);
		main_char=0;
		hyoujou=0;
		view.setBitmap(0,0);
		view.invalidate();
		Toast.makeText(this, "キャラクターメニューが範囲外になりデフォルトが実行されました。", Toast.LENGTH_LONG).show();;
		break;
	}
	return true;
}

//メニューを動的に差し替える。
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
	super.onPrepareOptionsMenu(menu);
	MenuItem smenu=menu.findItem(MENU_ID_3);//メニューから子メニューがあるアイテムを取得する。
	SubMenu  submenu= smenu.getSubMenu();//アイテムから、子メニューを参照する。

        //キャラによって、表示する子メニューのグループを切り替える。
	switch (main_char) {
	case 0:
		//flandre
		submenu.setGroupVisible(GM_ID0, true);
		submenu.setGroupVisible(GM_ID1, false);
		submenu.setGroupVisible(GM_ID2, false);
		break;
	case 1:
		//remilia
		submenu.setGroupVisible(GM_ID0, false);
		submenu.setGroupVisible(GM_ID1, true);
		submenu.setGroupVisible(GM_ID2, false);
		break;
	case 2:
		//sakuya
		submenu.setGroupVisible(GM_ID0, false);
		submenu.setGroupVisible(GM_ID1, false);
		submenu.setGroupVisible(GM_ID2, true);
		break;
	case 3:
		break;
	default:
		//メニューが範囲外起こして、デフォルトになるようなら、元のフランに戻す
		submenu.setGroupVisible(GM_ID0, true);
		submenu.setGroupVisible(GM_ID1, false);
		submenu.setGroupVisible(GM_ID2, false);
		main_char=0;
		hyoujou=0;
		view.setBitmap(0,0);
		view.invalidate();
		Toast.makeText(this, "キャラクターメニューが範囲外になりデフォルトが実行されました。", Toast.LENGTH_LONG).show();;
		break;
	}
	return super.onPrepareOptionsMenu(menu);
}

//メニューボタンが押されたら実行される所
public boolean onOptionsItemSelected(MenuItem item) {
	//メニューで該当するボタンが押された時の処理
	switch (item.getItemId()) {
	case MENU_ID_0:
		//保存
		view.hozon();
		return true;
       //~中省略~

	case SUB_MENU_ID0:
		hyoujou=0;
		view.setBitmap(hyoujou,main_char);
		view.invalidate();
		return true;

	case SUB_MENU_ID1:
		hyoujou=1;
		view.setBitmap(hyoujou,main_char);
		view.invalidate();
		return true;

	case SUB_MENU_ID2:
		hyoujou=2;
		view.setBitmap(hyoujou,main_char);
		view.invalidate();
		return true;
       //~中省略~


	case SUB_MENU2_ID0:
		main_char=0;
		view.setBitmap(hyoujou,main_char);
		view.invalidate();

		return true;
	case SUB_MENU2_ID1:
		main_char=1;
		view.setBitmap(hyoujou,main_char);
		view.invalidate();
		return true;
	case SUB_MENU2_ID2:
		main_char=2;
		view.setBitmap(hyoujou,main_char);
		view.invalidate();
		return true;

	default:
		break;
	}
	return false;
}

まず、onCreateOptionsMenuで、普通にサブメニューを作る。
その際に、第1引数に、切りたいグループ毎に固有の番号(グループID)を与えて、グループ化のメタファーを置くことが重要。オーダーはどうでもいい。
全てのメニューを最初に登録することも重要。

Switch Caseは、このブログ 情報によると、onPrepareOptionsMenuは、アプリが起動したときは実行されないらしいので、保存した値を見て、設定し直している。

続いて、onPrepareOptionsMenuメソッド。今回の肝。
submenu変数は、onCreateOptionsMenuの外なので、変数の有効範囲外。ここの解説が、webから見つけられなくて困った。なので試行錯誤の結果動いた。
MenuItem smenu=menu.findItem(MENU_ID_3);この行で、サブメニューのあるメニューIDを指定する。この場合MENU_ID_3。そしてもう1クッション。
SubMenu  submenu= smenu.getSubMenu();でやっとサブメニューの取得が出来る。
主読できたサブメニューを使って、submenu.setGroupVisible(GM_ID0, true);のsetGroupVisibleを実行する。
GM_ID0の部分がonCreateOptionsMenuで指定したグループID。第2引数のTrueならメニューを表示する。Falseなら、メニューを表示しない。
これを、キャラクターの番号を示す変数、main_charごとに分岐して、キャラクターごとに適切な設定をしてあげる。これで完成。

※なおこのコードは、setGroupCheckableを実行する必要が無い。
なので、わざわざラジオボタンやチェックボックスグループとしてバウンドする必要が無い。
これはかなりのメリット。

onOptionsItemSelectedは、メニューを押された時の処理なので、onCreateOptionsMenuの時に第2引数で指定してあげた部分だ。 今回の肝は、subMenu.addMenu.NONE ,SUB_MENU_ID0 , Menu.NONE, "通常");でサブメニューを作っていたものを、 subMenu.add(GM_ID1,SUB_MENU_ID0 , Menu.NONE, "通常");のように第1引数にグループIDを振って、全部の選択肢を作る。 MenuItem smenu=menu.findItem(MENU_ID); SubMenu  submenu= smenu.getSubMenu(); をやって、サブメニューへアクセスできるようにしてあげる。 subMenu.setGroupVisible(GM_ID1, false); 変数を使って、メニューの、可視・不可視を決めてあげる。 ここまでだ。

onOptionsItemSelectedメソッドは、subMenu.addの第2引数で決めたIDをいつものように列挙してあげれば、良きに処理してくれる。 いつものメニューの使い方と変わらないのでそこまで重要じゃない。

以上、簡単かつ適当だが、Androidのオプションメニューを切り替えたい場合の備忘録。 尚、Androidの2.3.3のエミュレータで動いただけなので実機で動かなくても知らないし、このコードを使って自分の身が破滅しても、私は一切の責任を負わない。

« 天気図作成ソフト3種を比較する | トップページ | 図書館総合展2014(第16回) »

プログラミング」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック


この記事へのトラックバック一覧です: Androidのオプションメニューを動的に変える方法:

« 天気図作成ソフト3種を比較する | トップページ | 図書館総合展2014(第16回) »