2012年3月20日火曜日

Android ActionBar の withText で文字がでる条件はどこで決まる?

ActionBar に表示する Action Item はこれまでのメニュー項目と同じように XML で定義できます。 <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/menu_edit" android:icon="@android:drawable/ic_menu_edit" android:showAsAction="ifRoom|withText" android:title="Edit"/> <item android:id="@+id/menu_save" android:showAsAction="ifRoom" android:title="Save"/> <item android:id="@+id/menu_delete" android:icon="@android:drawable/ic_menu_delete" android:showAsAction="ifRoom" android:title="Delete"/> </menu>
android:showAsAction に ifRoom を指定すると領域があるときは Action Item として表示されます。

android:icon が指定されていないときは android:title に指定されている文字列が表示されますが、 android:icon が指定されていたらデフォルトでは android:title の文字列は表示されません。

android:showAsAction に withText を指定すると、

 ハンドセット縦画面 : アイコンだけ
 ハンドセット横画面 : アイコン + 文字列
 タブレット縦画面 : アイコン + 文字列
 タブレット横画面 : アイコン + 文字列

のような表示になります。

ハンドセット縦画面


ハンドセット横画面


この条件がどこで決まっているのか調べました。

---

まず、Menu オブジェクトの View を作っているベースクラスが BaseMenuPresentar です。このクラスは MenuPresenter インタフェースを実装しています。 このクラスのコンストラクタで指定されたリソースID (mMenuLayoutRes) が
53 public BaseMenuPresenter(Context context, int menuLayoutRes, int itemLayoutRes) { 54 mSystemContext = context; 55 mSystemInflater = LayoutInflater.from(context); 56 mMenuLayoutRes = menuLayoutRes; 57 mItemLayoutRes = itemLayoutRes; 58 }
getMenuView でインフレートされて Menu の View として返されます。
67 @Override 68 public MenuView getMenuView(ViewGroup root) { 69 if (mMenuView == null) { 70 mMenuView = (MenuView) mSystemInflater.inflate(mMenuLayoutRes, root, false); 71 mMenuView.initialize(mMenu); 72 updateMenuView(true); 73 } 74 75 return mMenuView; 76 }
この BaseMenuPresenter のインスタンスを生成しているのが ActionMenuPresenter です。
71 public ActionMenuPresenter(Context context) { 72 super(context, com.android.internal.R.layout.action_menu_layout, 73 com.android.internal.R.layout.action_menu_item_layout); 74 }
145 @Override 146 public MenuView getMenuView(ViewGroup root) { 147 MenuView result = super.getMenuView(root); 148 ((ActionMenuView) result).setPresenter(this); 149 return result; 150 }
つまり、com.android.internal.R.layout.action_menu_item_layout がメニューのレイアウトになります。

このレイアウトのルートは com.android.internal.view.menu.ActionItemMenuView になっています。

この ActionItemMenuView の updateTextButtonVisibility() メソッドで文字列の表示/非表示をセットしています。
132 private void updateTextButtonVisibility() { 133 boolean visible = !TextUtils.isEmpty(mTextButton.getText()); 134 visible &= mImageButton.getDrawable() == null || 135 (mItemData.showsTextAsAction() && (mAllowTextWithIcon || mExpandedFormat)); 136 137 mTextButton.setVisibility(visible ? VISIBLE : GONE); 138 }
ここを見ると、文字列が表示される条件は

 ・文字列が空ではない
    +
 ・アイコンが指定されていない

もしくは、

 ・文字列が空ではない
    +
 ・android:showAsAction に withText がセットされている
    +
 ・mAllowTextWithIcon もしくは mExpandedFormat が true

であることがわかります。


ハンドセットの縦/横で文字列が出ない/出るの違いを決めているのは

 ・mAllowTextWithIcon もしくは mExpandedFormat が true

の部分です。
37 public class ActionMenuItemView extends LinearLayout 38 implements MenuView.ItemView, View.OnClickListener, View.OnLongClickListener, 39 ActionMenuView.ActionMenuChildView { ... 48 private boolean mAllowTextWithIcon; ... 50 private boolean mExpandedFormat;
まず、mExpandedFormat についてみると setExpandFormat() メソッドで外部から設定するしかありません。
123 public void setExpandedFormat(boolean expandedFormat) { 124 if (mExpandedFormat != expandedFormat) { 125 mExpandedFormat = expandedFormat; 126 if (mItemData != null) { 127 mItemData.actionFormatChanged(); 128 } 129 } 130 }
しかし、このメソッドを呼んでいるところがなかったので、現状では常に boolean の初期値の false になってるようです。

次に、mAllowTextWithIcon です。

この変数には、 ActionMenuItemView のコンストラクタで、com.android.internal.R.bool.config_allowActionMenuItemTextWithIcon の値がセットされています。

60 public ActionMenuItemView(Context context, AttributeSet attrs, int defStyle) { 61 super(context, attrs, defStyle); 62 final Resources res = context.getResources(); 63 mAllowTextWithIcon = res.getBoolean( 64 com.android.internal.R.bool.config_allowActionMenuItemTextWithIcon); 65 mShowTextAllCaps = res.getBoolean(com.android.internal.R.bool.config_actionMenuItemAllCaps); 66 }

com.android.internal.R.bool.config_allowActionMenuItemTextWithIcon の値がどうなっているかをみると、

res/values/config.xml
708 <!-- Whether action menu items should obey the "withText" showAsAction 709 flag. This may be set to false for situations where space is 710 extremely limited. --> 711 <bool name="config_allowActionMenuItemTextWithIcon">false</bool>
res/values-w480dp/config.xml
20 <bool name="config_allowActionMenuItemTextWithIcon">true</bool>
つまり、横幅が 480dp より大きい画面の向きでは mAllowTextWithIcon が true になり、Action Item にアイコン + 文字列が表示されるということでしたー。



0 件のコメント:

コメントを投稿