更改选项菜单的背景颜色 [英] Change the background color of the options menu

查看:160
本文介绍了更改选项菜单的背景颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图更改默认的颜色选项菜单中是白色的。我希望有一个黑色背景的选项菜单上的每一个项目。我已经尝试了一些笋Android这样的:在菜单元素中的项目元素itemBackground =#000000,但它不工作。 我不知道这是可行与否。任何想法会受到欢迎! :)

解决方案

这显然是一个问题,很多程序员都并到谷歌还没有提供令人满意的,支持的解决方案。

有很多交叉的意图和误解左右浮动的帖子关于这个主题,所以请回答问题前阅读本全部答案。

下面我有一个更精和良好注释的版本,从其他答案这个页面上的黑客攻击,并列入想法从这些密切相关的问题:

Android的菜单

更改背景颜色

<一个href="http://stackoverflow.com/questions/2944244/change-the-background-color-of-the-options-menu">Change选项​​菜单的背景颜色

<一个href="http://stackoverflow.com/questions/1593529/android-customize-applications-menu-e-g-background-color">Android:自定义应用程序的菜单(如背景色)

<一个href="http://www.macadamian.com/blog/post/android_-_theming_the_unthemable/">http://www.macadamian.com/blog/post/android_-_theming_the_unthemable/

Android的菜单项切换按钮

<一个href="http://stackoverflow.com/questions/3217886/is-is-possible-to-make-the-android-options-menu-background-non-translucent">Is可以使Android的选项菜单背景非透明?

<一个href="http://www.$c$cproject.com/KB/android/AndroidMenusMyWay.aspx">http://www.$c$cproject.com/KB/android/AndroidMenusMyWay.aspx

设置菜单背景是不透明的

我测试了这个技巧在2.1(模拟器),2​​.2(2真机)和2.3(2真正的设备)。我没有任何3.X平板电脑上测试,不过也将张贴任何必要的更改这里的时候,/如果我这样做。考虑到3.X平板电脑使用的动作条,而不是选项菜单,如下解释:

<一个href="http://developer.android.com/guide/topics/ui/menus.html#options-menu">http://developer.android.com/guide/topics/ui/menus.html#options-menu

这个技巧几乎肯定会做3.X平板电脑没什么(没有伤害,没有好)。

问题的声明(前触发回答了负面评论阅读)

Options(选项)菜单中有不同的设备上完全不同的风格。纯黑色带一些,纯白色与一些黑色文本白色文本。我和许多其他开发商希望控制选项的背景色菜单单元格的以及选项菜单文本的颜色

某些应用程序开发人员只需要设置单元格背景色(而不是文本颜色),并且可以在一个更清洁的方式使用了android做到这一点:在其他的答案中描述panelFullBackground风格。但是,目前还没有办法控制选项菜单文字的颜色与款式,所以人们只能用这种方法来改变背景,以另一种颜色,不会使文字消失。

我们很乐意与记录的,面向未来的解决方案,做到这一点,但一个是根本不能作为Android的&LT的; = 2.3。因此,我们必须使用的解决方案能在目前的版本中,旨在最大限度地减少碰撞/打破在未来的版本的机会。我们需要一个解决方案,无法正常返回到默认的行为,如果它失败。

有许多合法的原因,人们可能需要控制选项菜单的外观(通常以匹配的视觉风格的应用程序的其余部分),所以我不会在那住。

有张贴有关这一个谷歌Android的错误:请通过主演的这个bug添加您的支持(注意谷歌不鼓励跟风的评论:只是一个明星就够了):

<一个href="http://$c$c.google.com/p/android/issues/detail?id=4441">http://$c$c.google.com/p/android/issues/detail?id=4441

解决方案内容至今:

若干海报建议涉及LayoutInflater.Factory黑客攻击。建议的破解工作为Android&LT; = 2.2并未能为Android 2.3,因为黑客取得了一个未公开的假设:一个人可以调用LayoutInflater.getView()的情况下直接在当前同LayoutInflater实例是调用LayoutInflater.inflate()内。新的code中的Andr​​oid 2.3打破了这个假设,并导致一个NullPointerException异常。

下面我稍微细化黑客不依赖于这一假设。

此外,黑客还依赖于使用内部,无证类名com.android.internal.view.menu.IconMenuItemView作为一个字符串(而不是作为一个Java类型)。我看不出有什么办法避免这种情况,仍然实现了既定目标。然而,这是可以做到的黑客,这将落入回来,如果com.android.internal.view.menu.IconMenuItemView没有出现在当前系统上谨慎的方式。

再次明白这是一个黑客,并绝不是我,声称这会在所有的平台上。但是,我们的开发人员不是生活在一个幻想的学术世界里,一切都必须经书:我们有一个要解决的问题,我们必须解决这个问题的最好的,我们能。例如,它似乎是不可能的com.android.internal.view.menu.IconMenuItemView将存在于3.X平板电脑,因为它们使用的选项菜单的动作条代替。

最后,一些开发商已经解决了这个问题,通过完全燮pressing了Android选项菜单,写自己的菜单类(某些环节上图)。我没有试过,但如果你有时间写自己的视图,并找出如何更换Android的观点(我敢肯定,魔鬼在这里的细节),那么它可能是一个很好的解决方案,不需要任何无证黑客。

HACK:

下面是code。

要使用code,从活动的onCreate()或活动onCreateOptionsMenu()调用addOptionsMenuHackerInflaterFactory()一次。它设置一个默认的工厂,这将影响后续创建的任何选项菜单。它不影响选项菜单已经创建了(在previous黑客使用setMenuBackground(),这是非常误导,因为该函数不设置任何菜单的属性在返回之前的函数名)。

  @燮pressWarnings(rawtypes)
静态类IconMenuItemView_class = NULL;
@燮pressWarnings(rawtypes)
静态构造函数IconMenuItemView_constructor = NULL;

//构造标准的签名预计的所有视图类气筒
@燮pressWarnings(rawtypes)
私有静态final类[] standard_inflater_constructor_signature =
新等级[] {Context.class,AttributeSet.class};

保护无效addOptionsMenuHackerInflaterFactory()
{
    最后LayoutInflater INFL = getLayoutInflater();

    infl.setFactory(新厂()
    {
        公共查看onCreateView(最后的字符串名称,
                                 最后上下文的背景下,
                                 最后的AttributeSet ATTRS)
        {
            如果(!name.equalsIgnoreCase(com.android.internal.view.menu.IconMenuItemView))
                返回null; //使用普通充气

            查看查看= NULL;

            //com.android.internal.view.menu.IconMenuItemView
            //  - 是一个内部的Java类的名称
            //  - 存在于Android的&LT; = 3.2,并可能超越
            //  - 可能会或可能不会在其他Android转速存在
            //  - 就是我们要修改设置背景等的实例类
            //  - 是我们要实例化的标准构造方法的类:
            // IconMenuItemView(背景下,ATTRS)
            //  - 这是LayoutInflater做什么,如果我们返回null
            //  - 不幸的是,我们不能只要致电:
            // infl.createView(姓名,空,ATTRS);
            //这里是因为在Android 3.2(也可能更高版本):
            // 1 CreateView的()只能充气内被称为()
            //因为充气()设置范围内的参数,最终
            //传递给IconMenuItemView构造函数的第一个参数,
            //将其存储在一个LayoutInflater实例变量。
            // 2。我们都在里面充气()
            // 3,但是从LayoutInflater的不同实例(而不是INFL)
            // 4。有没有办法让进入实际情况使用
            //  - 所以我们必须做什么CreateView的()会为我们做
            //
            如果(IconMenuItemView_class == NULL)
            {
                尝试
                {
                    IconMenuItemView_class = getClassLoader()的loadClass(名称)。
                }
                赶上(ClassNotFoundException的E)
                {
                    //这个操作系统没有IconMenuItemView  - 失败优雅
                    返回null; //破解失败:正常使用充气
                }
            }
            如果(IconMenuItemView_class == NULL)
                返回null; //破解失败:正常使用充气

            如果(IconMenuItemView_constructor == NULL)
            {
                尝试
                {
                    IconMenuItemView_constructor =
                    IconMenuItemView_class.getConstructor(standard_inflater_constructor_signature);
                }
                赶上(SecurityException异常E)
                {
                    返回null; //破解失败:正常使用充气
                }
                赶上(NoSuchMethodException E)
                {
                    返回null; //破解失败:正常使用充气
                }
            }
            如果(IconMenuItemView_constructor == NULL)
                返回null; //破解失败:正常使用充气

            尝试
            {
                [对象]的args =新的对象[] {背景下,ATTRS};
                鉴于=(查看)(IconMenuItemView_constructor.newInstance(参数));
            }
            赶上(抛出:IllegalArgumentException E)
            {
                返回null; //破解失败:正常使用充气
            }
            赶上(InstantiationException E)
            {
                返回null; //破解失败:正常使用充气
            }
            赶上(IllegalAccessException E)
            {
                返回null; //破解失败:正常使用充气
            }
            赶上(的InvocationTargetException E)
            {
                返回null; //破解失败:正常使用充气
            }
            如果理论(空==视图)//上面的处理,但安全...
                返回null; //破解失败:正常使用充气


            //应用我们自己的视图设置后,我们回到runloop
            //  -  Android将覆盖几乎所有的,我们现在做的设置
            最终的视图V =视图;
            新的处理程序()。后(新的Runnable()
            {
                公共无效的run()
                {
                    v.setBackgroundColor(Color.BLACK);

                    尝试
                    {
                        //在Android的&LT; = 3.2,IconMenuItemView与TextView的实施
                        //防止在实施未来可能的变化
                        TextView的电视=(TextView中)V;
                        tv.setTextColor(Color.WHITE);
                    }
                    赶上(ClassCastException异常E)
                    {
                        //黑客失败:没有设置TextView的属性
                    }
                }
            });

            返回查看;
        }
    });
}
 

感谢您的阅读和享受!

I'm trying to change the default color for the options menu which is white. I want a black background for every item on the options menu. I've tried some shoots like android:itemBackground="#000000" on the item element within the menu element but it doesn't work. I don't know if this is doable or not. Any idea would be welcome! :)

解决方案

This is clearly a problem that a lot of programmers have and to which Google has yet to provide a satisfactory, supported solution.

There are a lot of crossed intentions and misunderstandings floating around posts on this topic, so please read this whole answer before responding.

Below I include a more "refined" and well-commented version of the hack from other answers on this page, also incorporating ideas from these very closely related questions:

Change background color of android menu

Change the background color of the options menu

Android: customize application's menu (e.g background color)

http://www.macadamian.com/blog/post/android_-_theming_the_unthemable/

Android MenuItem Toggle Button

Is is possible to make the Android options menu background non-translucent?

http://www.codeproject.com/KB/android/AndroidMenusMyWay.aspx

Setting the menu background to be opaque

I tested this hack on 2.1 (simulator), 2.2 (2 real devices), and 2.3 (2 real devices). I don't have any 3.X tablets to test on yet but will post any needed changes here when/if I do. Given that 3.X tablets use Action Bars instead of Options Menus, as explained here:

http://developer.android.com/guide/topics/ui/menus.html#options-menu

this hack will almost certainly do nothing (no harm and no good) on 3.X tablets.

STATEMENT OF THE PROBLEM (read this before trigger-replying with a negative comment):

The Options menu has vastly different styles on different devices. Pure black with white text on some, pure white with black text on some. I and many other developers wish to control the background color of the Options menu cells as well as the color of the Options menu text.

Certain app developers only need to set the cell background color (not the text color), and they can do this in a cleaner manner using the android:panelFullBackground style described in another answer. However, there is currently no way to control the Options menu text color with styles, and so one can only use this method to change the background to another color that won't make the text "disappear."

We would love to do this with a documented, future-proof solution, but one is simply not available as of Android <= 2.3. So we have to use a solution that works in current versions and is designed to minimize the chances of crashing/breaking in future versions. We want a solution that fails gracefully back to the default behavior if it has to fail.

There are many legitimate reasons why one may need to control the look of Options menus (typically to match a visual style for the rest of the app) so I won't dwell on that.

There is a Google Android bug posted about this: please add your support by starring this bug (note Google discourages "me too" comments: just a star is enough):

http://code.google.com/p/android/issues/detail?id=4441

SUMMARY OF SOLUTIONS SO FAR:

Several posters have suggested a hack involving LayoutInflater.Factory. The suggested hack worked for Android <= 2.2 and failed for Android 2.3 because the hack made an undocumented assumption: that one could call LayoutInflater.getView() directly without currently being inside a call to LayoutInflater.inflate() on the same LayoutInflater instance. New code in Android 2.3 broke this assumption and led to a NullPointerException.

My slightly refined hack below does not rely on this assumption.

Furthermore, the hacks also rely on using an internal, undocumented class name "com.android.internal.view.menu.IconMenuItemView" as a string (not as a Java type). I do not see any way to avoid this and still accomplish the stated goal. However, it is possible to do the hack in a careful way that will fall back if "com.android.internal.view.menu.IconMenuItemView" does not appear on the current system.

Again, understand that this is a hack and by no means am I claiming this will work on all platforms. But we developers are not living in a fantasy academic world where everything has to be by the book: we have a problem to solve and we have to solve it as best we can. For example, it seems unlikely that "com.android.internal.view.menu.IconMenuItemView" will exist on 3.X tablets since they use Action Bars instead of Options Menus.

Finally, some developers have solved this problem by totally suppressing the Android Options Menu and writing their own menu class (see some of the links above). I haven't tried this, but if you have time to write your own View and figure out how to replace Android's view (I'm sure the devil's in the details here) then it might be a nice solution that doesn't require any undocumented hacks.

HACK:

Here is the code.

To use this code, call addOptionsMenuHackerInflaterFactory() ONCE from your activity onCreate() or your activity onCreateOptionsMenu(). It sets a default factory that will affect subsequent creation of any Options Menu. It does not affect Options Menus that have already been created (the previous hacks used a function name of setMenuBackground(), which is very misleading since the function doesn't set any menu properties before it returns).

@SuppressWarnings("rawtypes")
static Class       IconMenuItemView_class = null;
@SuppressWarnings("rawtypes")
static Constructor IconMenuItemView_constructor = null;

// standard signature of constructor expected by inflater of all View classes
@SuppressWarnings("rawtypes")
private static final Class[] standard_inflater_constructor_signature = 
new Class[] { Context.class, AttributeSet.class };

protected void addOptionsMenuHackerInflaterFactory()
{
    final LayoutInflater infl = getLayoutInflater();

    infl.setFactory(new Factory()
    {
        public View onCreateView(final String name, 
                                 final Context context,
                                 final AttributeSet attrs)
        {
            if (!name.equalsIgnoreCase("com.android.internal.view.menu.IconMenuItemView"))
                return null; // use normal inflater

            View view = null;

            // "com.android.internal.view.menu.IconMenuItemView" 
            // - is the name of an internal Java class 
            //   - that exists in Android <= 3.2 and possibly beyond
            //   - that may or may not exist in other Android revs
            // - is the class whose instance we want to modify to set background etc.
            // - is the class we want to instantiate with the standard constructor:
            //     IconMenuItemView(context, attrs)
            // - this is what the LayoutInflater does if we return null
            // - unfortunately we cannot just call:
            //     infl.createView(name, null, attrs);
            //   here because on Android 3.2 (and possibly later):
            //   1. createView() can only be called inside inflate(),
            //      because inflate() sets the context parameter ultimately
            //      passed to the IconMenuItemView constructor's first arg,
            //      storing it in a LayoutInflater instance variable.
            //   2. we are inside inflate(),
            //   3. BUT from a different instance of LayoutInflater (not infl)
            //   4. there is no way to get access to the actual instance being used
            // - so we must do what createView() would have done for us
            //
            if (IconMenuItemView_class == null)
            {
                try
                {
                    IconMenuItemView_class = getClassLoader().loadClass(name);
                }
                catch (ClassNotFoundException e)
                {
                    // this OS does not have IconMenuItemView - fail gracefully
                    return null; // hack failed: use normal inflater
                }
            }
            if (IconMenuItemView_class == null)
                return null; // hack failed: use normal inflater

            if (IconMenuItemView_constructor == null)
            {
                try
                {
                    IconMenuItemView_constructor = 
                    IconMenuItemView_class.getConstructor(standard_inflater_constructor_signature);
                }
                catch (SecurityException e)
                {
                    return null; // hack failed: use normal inflater
                }
                catch (NoSuchMethodException e)
                {
                    return null; // hack failed: use normal inflater
                }
            }
            if (IconMenuItemView_constructor == null)
                return null; // hack failed: use normal inflater

            try
            {
                Object[] args = new Object[] { context, attrs };
                view = (View)(IconMenuItemView_constructor.newInstance(args));
            }
            catch (IllegalArgumentException e)
            {
                return null; // hack failed: use normal inflater
            }
            catch (InstantiationException e)
            {
                return null; // hack failed: use normal inflater
            }
            catch (IllegalAccessException e)
            {
                return null; // hack failed: use normal inflater
            }
            catch (InvocationTargetException e)
            {
                return null; // hack failed: use normal inflater
            }
            if (null == view) // in theory handled above, but be safe... 
                return null; // hack failed: use normal inflater


            // apply our own View settings after we get back to runloop
            // - android will overwrite almost any setting we make now
            final View v = view;
            new Handler().post(new Runnable()
            {
                public void run()
                {
                    v.setBackgroundColor(Color.BLACK);

                    try
                    {
                        // in Android <= 3.2, IconMenuItemView implemented with TextView
                        // guard against possible future change in implementation
                        TextView tv = (TextView)v;
                        tv.setTextColor(Color.WHITE);
                    }
                    catch (ClassCastException e)
                    {
                        // hack failed: do not set TextView attributes
                    }
                }
            });

            return view;
        }
    });
}

Thanks for reading and enjoy!

这篇关于更改选项菜单的背景颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆