【问题标题】:Change ActionMode Overflow icon更改 ActionMode 溢出图标
【发布时间】:2014-03-28 18:43:20
【问题描述】:

有没有办法在不更改“正常”ActionBar 图标的情况下更改 ActionMode 溢出图标?

【问题讨论】:

    标签: android android-actionbar android-actionmode


    【解决方案1】:

    我仍然需要弄清楚如何只更改 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 对应ActionBarR.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 - 但我们不需要ActionBarlight 版本吗?是的 - 我们将在活动的 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。

    对于这个巨大的帖子,我深表歉意。我真的希望它有所帮助。

    【讨论】:

    • 这只是一个惊人的解释!你的第一个教程做得很好!在我看来,这比处理 Handlers 和 Runnables 更漂亮……谢谢! :))
    • 尝试了第一个带有样式的解决方案,适用于 Android 5.0 之前的版本,但不适用于 Android Lollipop 5.0。有这方面的更新吗?
    【解决方案2】:

    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 baraction modes 中构建操作菜单。因此,通过覆盖主题文件将在两种模式下应用相同的样式。完成的唯一方法是以编程方式完成 hereaction 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;
            }  
    
        }
    }
    

    【讨论】:

    • 谢谢!我已经看到了这种实现方式,但认为必须有一种方法可以在 xml 中实现。但是,您的解释非常好,我现在认为您建议的方式是做到这一点的唯一方法......享受赏金的乐趣(在 14 小时内......)
    • @Frame91 只是一个建议..充分利用您的赏金。您可以将此答案保持在未接受状态,以便其他人会尝试提供(可能是)更好的解决方案。当赏金接近到期时间时,您可以手动分配赏金。
    • 是的,你是对的 - 但正如你所解释的,没有人会提交一个简单的 xml 解决方案;)
    【解决方案3】:

    您应该能够使用样式来做到这一点:

    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 做了这个,但我需要 ActionBar 的 Holo.Dark 图标和 ActionMode 的 Holo.Light 图标。
    【解决方案4】:

    有没有办法在不更改“正常”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上“返回箭头”和“溢出图标”的颜色。

    【讨论】:

      【解决方案5】:

      在我的例子中,我只是想要三个点图标的不同颜色,为了实现它,我在我的主题中设置了&lt;item name="actionBarTheme"&gt;@style/Widget.ActionMode.ActionBar&lt;/item&gt;Widget.ActionMode.ActionBar 如下所示:

          <style name="Widget.ActionMode.ActionBar" parent="@style/ThemeOverlay.AppCompat.Light">
              <item name="colorControlNormal">the color I want</item>
          </style>
      

      【讨论】:

        猜你喜欢
        • 2015-03-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-01
        • 2023-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多