メニューのレイアウトを動的に変更する


Android4.0(以降ICS)ではメニューを再描画させるためのメソッド“invalidateOptionsMenu”がFragmentManagerクラスに追加されました。

このinvalidateOptionsMenuメソッドはActivityクラスではAndroid3.0(API level11)から追加されていますが、Fragmentからメニューの再描画を促したい場合はFragmentManager#invalidateOptionsMenuを使用することが必須となっています。

このinvalidateOptionsMenuメソッドを使用することで動的にメニューのレイアウトを変更することが可能になります。

invalidateOptionsMenuメソッドの詳細は以下から。

invalidateOptionsMenuを使用したメニューのレイアウトの変更方法

invalidateOptionsMenuメソッドが呼び出されるとActivityクラスのonCreateOptionsMenuメソッドが呼ばれます。

メニューのレイアウトを変更したい場合はメニューのレイアウトのバリエーションをメニューのレイアウトファイルに定義しておいて、メニューのレイアウトを管理する変数を用意し、onCreateOptionsMenuメソッドではレイアウト管理用の変数ごとに読み込むメニューのレイアウトファイルを変更する実装がシンプルでコードの可読性も上がります。

下記のサンプルはmMenuTypeというメニューのレイアウト管理用変数を用意して、その中身の状態によって読み込むメニューのレイアウトファイルを切り替えています。

InvalidateOptionsMenuSampleActivity.java

/**
 * メニューレイアウト管理用変数
 */
public static int mMenuType = 1;
/**
 * メニューのレイアウトファイルmenu_aを表す
 */
public static final int MENU_TYPE_A = 1;
/**
 * メニューのレイアウトファイルmenu_bを表す
 */
public static final int MENU_TYPE_B = 2;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Button btn = (Button) findViewById(R.id.change_menu_button);
    btn.setOnClickListener(this);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // メニューレイアウト管理用変数が切り替わる度にメニューのレイアウトを切り替える
    switch (mMenuType) {
        case MENU_TYPE_A:
            getMenuInflater().inflate(R.menu.menu_a, menu);
            break;
        case MENU_TYPE_B:
            getMenuInflater().inflate(R.menu.menu_b, menu);
            break;
        default:
        break;
    }

    return super.onCreateOptionsMenu(menu);
}

メニューのレイアウトを切り替える仕組みができたところで、実際にFragmentからメニューを更新してみましょう。

まず、InvalidateOptionsMenuSampleActivity.javaにFragmentをコミットするための処理を追加します。

下記のコードでは画面内のボタンが押下される度にFragmentがコミットされます。

InvalidateOptionsMenuSampleActivity.java

public void onClick(View v) {
    // フラグメントをコミットする
    InvalidateOptionsMenuFragment fragment = new InvalidateOptionsMenuFragment();
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    ft.add(R.id.sample_fragment, fragment);
    ft.commit();
}

次にInvalidateOptionsMenuFragmentのコードを下記に記述します。

このFragmentはonResumeが呼ばれる度に親Activityのメニューレイアウト管理用変数を変更し、メニューの再描画を行います。

InvalidateOptionsMenuFragment.java

public class InvalidateOptionsMenuFragment extends Fragment{

	public InvalidateOptionsMenuFragment() {
	}

	@Override
	public void onResume() {
		super.onResume();

		// 親Activityのメニュー管理用変数を切り替える
		switch (InvalidateOptionsMenuSampleActivity.mMenuType) {
		case InvalidateOptionsMenuSampleActivity.MENU_TYPE_A:
			InvalidateOptionsMenuSampleActivity.mMenuType = InvalidateOptionsMenuSampleActivity.MENU_TYPE_B;
			break;
		case InvalidateOptionsMenuSampleActivity.MENU_TYPE_B:
			InvalidateOptionsMenuSampleActivity.mMenuType = InvalidateOptionsMenuSampleActivity.MENU_TYPE_A;
			break;
		default:
			break;
		}
		getFragmentManager().invalidateOptionsMenu();
	}
}

21行目でFragmentManager#invalidateOptionsMenuメソッドを使用して、親Activityのメニューを再描画しています。

3 Comments