以下は、Android UI Cookbook for 4.0 で紹介した方法(android:itemBackground を指定する方法)で、押したとき背景が半透明の赤になるようにした場合です。
赤とデフォルトの水色が混ざって、紫っぽくなってしまっています。
これは、半透明の赤の下にデフォルトの水色の selector も表示されているからです。
これを修正する方法は2つあります。
- 1. android:itemBackground には何も指定せず、下の水色の selector を変更する
- 2. android:itemBackground を指定して、下の水色の selector に透明を指定する
結論としては、android:listChoiceBackgroundIndicator を利用します。この属性は API Level 11 からですが、Support Library v7 の appcompat でも対応しています。
res/values/styles.xml
原因はまだ見つけてません。ぐぬぬ
2013.12.3 追記
原因&解決方法を見つけました!
Theme.Holo.Light.DarkActionBar でセットされている属性を一つずつ追加していったところ、
- @android:style/Theme.Holo
が原因だということがわかりました。Theme.Holo および Theme.Holo.Light ではこの属性には @null が指定されています。
この属性は ActionBarImpl クラスで利用されています。
http://tools.oesf.biz/android-4.4.0_r1.0/xref/frameworks/base/core/java/com/android/internal/app/ActionBarImpl.java#800
800 public Context getThemedContext() {
801 if (mThemedContext == null) {
802 TypedValue outValue = new TypedValue();
803 Resources.Theme currentTheme = mContext.getTheme();
804 currentTheme.resolveAttribute(com.android.internal.R.attr.actionBarWidgetTheme,
805 outValue, true);
806 final int targetThemeRes = outValue.resourceId;
807
808 if (targetThemeRes != 0 && mContext.getThemeResId() != targetThemeRes) {
809 mThemedContext = new ContextThemeWrapper(mContext, targetThemeRes);
810 } else {
811 mThemedContext = mContext;
812 }
813 }
814 return mThemedContext;
815 }
そこで、Theme.Holo を継承し android:listChoiceBackgroundIndicator をセットしたテーマを別途用意し、android:actionBarWidgetTheme に指定するようにしたところうまくいきました。
■ 詳細解説
Overflow Menu は ListPopupWindow です。
http://tools.oesf.biz/android-4.4.0_r1.0/xref/frameworks/base/core/java/com/android/internal/view/menu/MenuPopupHelper.java#122
122 public boolean tryShow() {
123 mPopup = new ListPopupWindow(mContext, null, com.android.internal.R.attr.popupMenuStyle);
124 mPopup.setOnDismissListener(this);
125 mPopup.setOnItemClickListener(this);
126 mPopup.setAdapter(mAdapter);
127 mPopup.setModal(true);
128
129 View anchor = mAnchorView;
130 if (anchor != null) {
131 final boolean addGlobalListener = mTreeObserver == null;
132 mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest
133 if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this);
134 anchor.addOnAttachStateChangeListener(this);
135 mPopup.setAnchorView(anchor);
136 mPopup.setDropDownGravity(mDropDownGravity);
137 } else {
138 return false;
139 }
140
141 if (!mHasContentWidth) {
142 mContentWidth = measureContentWidth();
143 mHasContentWidth = true;
144 }
145
146 mPopup.setContentWidth(mContentWidth);
147 mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
148 mPopup.show();
149 mPopup.getListView().setOnKeyListener(this);
150 return true;
151 }
ListPopupWindow には setListSelector() というメソッドが用意されています。
http://tools.oesf.biz/android-4.4.0_r1.0/xref/frameworks/base/core/java/android/widget/ListPopupWindow.java
350 public void setListSelector(Drawable selector) {
351 mDropDownListHighlight = selector;
352 }
...
971 private int buildDropDown() {
1015 private int buildDropDown() {
1016 ViewGroup dropDownView;
1017 int otherHeights = 0;
1018
1019 if (mDropDownList == null) {
1020 Context context = mContext;
1021
1022 /**
1023 * This Runnable exists for the sole purpose of checking if the view layout has got
1024 * completed and if so call showDropDown to display the drop down. This is used to show
1025 * the drop down as soon as possible after user opens up the search dialog, without
1026 * waiting for the normal UI pipeline to do it's job which is slower than this method.
1027 */
1028 mShowDropDownRunnable = new Runnable() {
1029 public void run() {
1030 // View layout should be all done before displaying the drop down.
1031 View view = getAnchorView();
1032 if (view != null && view.getWindowToken() != null) {
1033 show();
1034 }
1035 }
1036 };
1037
1038 mDropDownList = new DropDownListView(context, !mModal);
1039 if (mDropDownListHighlight != null) {
1040 mDropDownList.setSelector(mDropDownListHighlight);
1041 }
...
しかし、MenuPopupHelper では、setListSelector() を呼んでくれていません。
ListPopupWindow 内のリストは、DropDownListView です。 このクラスは ListPopupWindow の内部クラスです。
http://tools.oesf.biz/android-4.4.0_r1.0/xref/frameworks/base/core/java/android/widget/ListPopupWindow.java#1445
1445 public DropDownListView(Context context, boolean hijackFocus) {
1446 super(context, null, com.android.internal.R.attr.dropDownListViewStyle);
1447 mHijackFocus = hijackFocus;
1448 // TODO: Add an API to control this
1449 setCacheColorHint(0); // Transparent, since the background drawable could be anything.
1450 }
ここでは com.android.internal.R.attr.dropDownListViewStyle を defStyleAttr として渡しています。
よって、android:dropDownListViewStyle を指定すればいいということです。Holo テーマでどのようなスタイルになっているか見てみましょう。
http://tools.oesf.biz/android-4.4.0_r1.0/xref/frameworks/base/core/res/res/values/themes.xml
906
1221
Theme.Holo も Theme.Holo.Light も @android:style/Widget.Holo.ListView.DropDown がセットされています。
Widget.Holo.ListView.DropDown は Widget.Holo.ListView と同じで、Widget.Holo.ListView では android:divider として ?android:attr/listDivider を、android:listSelector として ?android:attr/listChoiceBackgroundIndicator をセットしています。
1649
1715
よって、android:listChoiceBackgroundIndicator に変更したい selector を指定すればいいということになります。
0 件のコメント:
コメントを投稿