Spinnerで作る「ドロップダウン式メインメニュー」

AndroidのUIコンポーネント「Spinner」は、いわゆるコンボボックス(ドロップダウンメニュー)です。

Spinnerは最初ボタン風に表示されていて、Spinnerのボタンを押すと下に選択項目が並んで表示されます。項目を選ぶと、onItemSelected()メソッドが呼び出されて選択項目に応じた処理を行えるわけですね。

このSpinnerは、不可視にしても動作する、つまり「選択項目が下に列挙される」機能を利用できるようです。setVisibility(View.INVISIBLE)とすると、上のボタンは表示されなくなりタッチなどで選択項目を開くこともできなくなりますが、コードでperformClick()を呼び出すと、ボタンをクリックしたときと同じようにドロップダウンメニューで選択肢が表示されるのです。

この機能を使うと、「メインメニュー風のドロップダウンメニュー」が簡単に実装できますね。Androidアプリ開発では、Androidのバージョンによって異なるメイン(トップ)メニューの扱いに困惑している開発者も多いはず。
Androidアプリ開発では、画面上に「タッチですぐに呼び出せるメインメニュー」を配置しようとしても、一筋縄ではいかないのです。

しかし、Spinnerを使えば「メインメニューに見えるドロップダウンメニュー」を簡単に実装することができます。

具体的な実装法は簡単で、「可視状態のButtonと不可視のSpinnerを含むFrameLayout」を作るだけ。FrameLayoutは、レイアウト自身がコンポーネントの配置(位置設定)を行いませんので、レイアウトパラメーターの設定を行わずに追加するとButtonとSpinnerが同位置に配置されることになります。

この状態で、「Buttonがクリックされたら、SpinnerのperformClick()を呼び出す」とどうなるでしょうか? そう「Buttonの下にドロップダウンメニュー形式でSpinnerに設定した選択肢が列挙される」わけですね。

あとは、このFrameLayoutを画面の上端に配置すれば、立派な(?)メインメニューになります。Activityのスタイル設定で、タイトルバーを非表示にすれば完璧でしょう。

実際に、以下のような実験クラスを作って試してみると、うまく機能しました。

import android.content.Context;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.Spinner;
import android.view.View.OnClickListener;

public class ButtonMenu extends FrameLayout implements OnClickListener {

	private Button mButton;
	private Spinner mSpinner;
	
	public ButtonMenu(Context context, String label, String[] items) {

		super(context);

		mButton = new Button(context);

		mButton.setText(label);
		mButton.setOnClickListener(this);

		addView(mButton);

		mSpinner = new Spinner(context);
		mSpinner.setVisibility(View.INVISIBLE);

		ArrayAdapter<String> adapter = new ArrayAdapter<String>(context, android.R.layout.simple_spinner_item, items);

		mSpinner.setAdapter(adapter);

		addView(mSpinner);

	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

		int width = right - left;
		int height = bottom - top;

		mButton.layout(0, 0, width - 1, height - 1);
		mSpinner.layout(0, 0, width - 1, height - 1);

	}

	@Override
	public void onClick(View view) {

		if (view == mButton) {
			mSpinner.performClick();
		}

	}

}

もちろん、この手法はAndroidの「メニューの流儀」にそったものではないですし、Androidのバージョンなどによってはうまく機能しない可能性もありますが……