【发布时间】:2014-03-28 18:43:20
【问题描述】:
有没有办法在不更改“正常”ActionBar 图标的情况下更改 ActionMode 溢出图标?
【问题讨论】:
标签: android android-actionbar android-actionmode
有没有办法在不更改“正常”ActionBar 图标的情况下更改 ActionMode 溢出图标?
【问题讨论】:
标签: android android-actionbar android-actionmode
我仍然需要弄清楚如何只更改 ActionMode-Actionbar 内的溢出图标,因为我更改了默认操作栏中的溢出图标,这在 ActionMode-Actionbar 中不可见(不,我不'不想改变我的 ActionMode-Actionbar 的背景!)
好的。
让我们从定义一些样式开始。我将尝试解释为什么我们以这种方式定义它们:
// This is just your base theme. It will probably include a lot more stuff.
// We are going to define the style 'OverflowActionBar' next.
<style name="BaseTheme" parent="android:Theme.Holo.Light">
....
....
....
<item name="android:actionOverflowButtonStyle">@style/OverflowActionBar</item>
</style>
// Assigning a parent to this style is important - we will inherit two attributes -
// the background (state-selector) and the content description
<style name="OverflowActionBar" parent="@android:style/Widget.Holo.ActionButton.Overflow">
<item name="android:src">@drawable/overflow_menu_light</item>
</style>
// Next up is an extension to our 'BaseTheme'. Notice the parent here.
<style name="ChangeOverflowToDark" parent="@style/BaseTheme">
<item name="android:actionOverflowButtonStyle">@style/OverflowActionMode</item>
</style>
// One last thing is to define 'OverflowActionMode'. Again, we inherit useful
// attributes by assigning 'Widget.Holo.ActionButton.Overflow' as the parent.
<style name="OverflowActionMode" parent="@android:style/Widget.Holo.ActionButton.Overflow">
<item name="android:src">@drawable/overflow_menu_dark</item>
</style>
我们与styles.xml 的所有工作都已完成。最后一点发生在运行时。我想你已经实现了ActionMode.Callback。
在您的活动中,定义一个方法 - changeOverflowIcon():
public void changeOverflowIcon() {
getTheme().applyStyle(R.style.ChangeOverflowToDark, true);
}
您将从 onCreateActionMode(...) 的 ActionMode.Callback 实现中调用此方法:
public class CustomActionModeCallback implements ActionMode.Callback {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
changeOverflowIcon()
// other initialization
return true;
}
@Override
public boolean onPrepareActionMode(final ActionMode mode, Menu menu) {
return true;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
@Override
public void onDestroyActionMode(ActionMode mode) {}
}
一点解释:
“BaseTheme”中的分配是针对ActionBar。它将选择可绘制的 overflow_menu_light,因为我们在您的应用程序的基本主题中分配它。
getTheme().applyStyle(R.style.ChangeOverflowToDark, true)
第二个参数true 强制当前主题用新属性覆盖旧属性。由于我们在ChangeOverflowToDark 中只定义了一个属性,所以它的值被覆盖了。 ActionBar 不受影响,因为它已经使用了旧属性。但是,动作模式尚未创建(当我们从onCreateActionMode(...) 返回true 时将创建它)。当操作模式检查此属性值时,它会获取新的值。
还有更多...
Manish 给出的答案非常棒。我从来没有想过使用内容描述来找到确切的ImageButton。 但是如果你可以使用简单的findViewById() 找到ImageButton 呢?
您可以这样做:
首先,我们需要唯一的 ID。如果您的项目当前没有res/values/ids.xml 文件,请创建一个。给它添加一个新的 id:
<item type="id" name="my_custom_id" />
我上面讨论的设置将保持不变。唯一的区别在于OverflowActionMode 风格:
<style name="OverflowActionMode" parent="@android:style/Widget.Holo.ActionButton.Overflow">
<item name="android:src">@drawable/overflow_menu_dark</item>
<item name="android:id">@id/my_custom_id</item>
</style>
当我们调用getTheme().applyStyle(R.style.ChangeOverflowToDark, true);时,我们上面定义的id会被分配给ImageButton
我将在此处从 Manish 的答案中借用代码 sn-p:
private ActionMode.Callback mCallback = new ActionMode.Callback()
{
@Override
public boolean onPrepareActionMode( ActionMode mode, Menu menu )
{
mDecorView.postDelayed(new Runnable() {
@Override
public void run() {
ImageButton btn = (ImageButton) mDecorView.findViewById(R.id.my_custom_id);
// Update the image here.
btn.setImageResource(R.drawable.custom);
}
}, 500); // 500 ms is quite generous // I would say that 50 will work just fine
return true;
}
}
两全其美?
假设我们需要R.drawable.overflow_menu_light 对应ActionBar 和R.drawable.overflow_menu_dark 对应ActionMode。
样式:
<style name="BaseTheme" parent="android:Theme.Holo.Light">
....
....
....
<item name="android:actionOverflowButtonStyle">@style/OverflowActionMode</item>
</style>
<style name="OverflowActionMode" parent="@android:style/Widget.Holo.ActionButton.Overflow">
<item name="android:src">@drawable/overflow_menu_dark</item>
<item name="android:id">@id/my_custom_id</item>
</style>
按照我们的风格定义,ActionBar 将选择R.drawable.overflow_menu_dark - 但我们不需要ActionBar 的light 版本吗?是的 - 我们将在活动的 onPrepareOptionsMenu(Menu) 回调中分配它:
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
ImageButton ib = (ImageButton)
getWindow().getDecorView()
.findViewById(R.id.my_custom_id);
if (ib != null)
ib.setImageResource(R.drawable.overflow_menu_light);
}
}, 50L);
return super.onPrepareOptionsMenu(menu);
}
我们在这里这样做是因为在onPrepareOptionsMenu(Menu) 之前,ImageButton 不会被创建。
现在,我们不需要处理ActionMode - 因为它会从主题中选择dark drawable。
对于这个巨大的帖子,我深表歉意。我真的希望它有所帮助。
【讨论】:
ImageButton 是用于显示菜单溢出的小部件。 actionOverflowButtonStyle 用于设置ImageButton 的样式。此样式应用于ActionMenuPresenter。
private class OverflowMenuButton extends ImageButton implements ActionMenuChildView {
public OverflowMenuButton(Context context) {
super(context, null, com.android.internal.R.attr.actionOverflowButtonStyle);
...
}
}
ActionMenuPresenter 类用于在action bar 和action modes 中构建操作菜单。因此,通过覆盖主题文件将在两种模式下应用相同的样式。完成的唯一方法是以编程方式完成 here 为 action bar。
这是action mode溢出图标的代码。您可以在ActionMode.Callback.onPrepareActionMode 方法中将drawable 分配给ImageButton。
public class MainActivity extends Activity {
ViewGroup mDecorView;
public void onCreate(Bundle savedInstanceState) {
// Assign mDecorView to later use in action mode callback
mDecorView = (ViewGroup) getWindow().getDecorView();
}
private ActionMode.Callback mCallback = new ActionMode.Callback()
{
@Override
public boolean onPrepareActionMode( ActionMode mode, Menu menu )
{
// We have to update the icon after it is displayed,
// hence this postDelayed variant.
// This is what I don't like, but it is the only way to move forward.
mDecorView.postDelayed(new Runnable() {
@Override
public void run() {
ArrayList<View> outViews = new ArrayList<View>();
// The content description of overflow button is "More options".
// If you want, you can override the style and assign custom content
// description and use it here.
mDecorView.findViewsWithText(outViews, "More Options", View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
if(!outViews.isEmpty()) {
View v = outViews.get(0);
if(v instanceof ImageButton) {
ImageButton btn = (ImageButton) v;
// Update the image here.
btn.setImageResource(R.drawable.custom);
}
}
}
}, 500);
return true;
}
}
}
【讨论】:
您应该能够使用样式来做到这一点:
ActionBarSherlock:
<style name="MyTheme" parent="Theme.Sherlock.Light">
<item name="actionOverflowButtonStyle">@style/MyTheme.OverFlow</item>
</style>
<style name="MyTheme.OverFlow" parent="Widget.Sherlock.ActionButton.Overflow">
<item name="android:src">@drawable/YOUR_ICON_GOES_HERE</item>
</style>
ActioBar:
<style name="MyTheme" parent="@android:style/Theme.Holo">
<item name="android:actionOverflowButtonStyle">@style/MyTheme.OverFlow</item>
</style>
<style name="MyTheme.OverFlow" parent="@android:style/Widget.Holo.ActionButton.Overflow">
<item name="android:src">@drawable/YOUR_ICON_GOES_HERE</item>
</style>
确保在清单中设置 MyTheme。
【讨论】:
有没有办法在不更改“正常”ActionBar 图标的情况下更改 ActionMode Overflow 图标?
关于如何更改溢出图标,我认为上面有很多答案。
如果你只是想改变溢出图标的颜色,可以使用简单的方法。
<style name="BaseAppTheme" parent="Theme.xxxx.Light.NoActionBar.xxx">
...
<item name="actionOverflowButtonStyle">@style/ActionMode.OverFlow</item>
</style>
<style name="ActionMode.OverFlow" parent="@style/Widget.AppCompat.ActionButton.Overflow">
<item name="android:tint">@color/black</item> #or any color you want.#
</style>
它对我有用。我调查了一下,看看这个截图http://prntscr.com/vqx1ov你就知道原因了。
而且我不建议设置colorControlNormal的颜色,它会改变ActionBar上“返回箭头”和“溢出图标”的颜色。
【讨论】:
在我的例子中,我只是想要三个点图标的不同颜色,为了实现它,我在我的主题中设置了<item name="actionBarTheme">@style/Widget.ActionMode.ActionBar</item>,Widget.ActionMode.ActionBar 如下所示:
<style name="Widget.ActionMode.ActionBar" parent="@style/ThemeOverlay.AppCompat.Light">
<item name="colorControlNormal">the color I want</item>
</style>
【讨论】: