Xamarin.Android Menu 添加 Icon 无效问题

问题分析

Android4.0 系统中,创建菜单 Menu,通过setIcon 方法给菜单添加图标是无效的,图标没有显出来,但在 Android 2.3 系统中是可以显示出来的。这个问题的根本原因在于 4.0 系统中,涉及到菜单的源码类 MenuBuilder 做了改变,该类的部分源码如下:

public class MenuBuilder implements Menu {  
    ...  
    private boolean mOptionalIconsVisible = false;  
    ...
    void setOptionalIconsVisible(boolean visible) {  
        mOptionalIconsVisible = visible;  
    }  
  
    boolean getOptionalIconsVisible() {  
        return mOptionalIconsVisible;  
    }  
    ...  
}  

上面的代码中,mOptionalIconsVisible 成员初始值默认为 false,这就是为什么给菜单设置图标没有效果的原因

解决思路

所以,只要我们在创建 Menu 时通过调用 setOptionalIconsVisible 方法设置 mOptionalIconsVisibletrue 就可以了。

难点:要想调用该方法,就需要创建 MenuBuilder对象,但是,我们是无法在开发的应用程序中创建 MenuBuilder 这个对象的 -- MenuBuilder 为系统内部的框架类

这时候就需要考虑用反射了,在代码运行创建菜单的时候通过反射调用 setOptionalIconsVisible 方法设置mOptionalIconsVisibletrue,然后在给菜单添加 Icon,这样就可以在菜单中显示添加的图标了

Java Code:

import java.lang.reflect.Method;
 
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
 
public class MainActivity extends Activity 
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        //运行时,参数Menu其实就是MenuBuilder对象
        Log.d("MainActivity", "menu--->" + menu);
        
        /*利用反射机制调用MenuBuilder的setOptionalIconsVisible方法设置mOptionalIconsVisible为true,
         * 给菜单设置图标时才可见
         */
        setIconEnable(menu, true);
        
        MenuItem item1 = menu.add(0, 1, 0, R.string.item1);
        item1.setIcon(R.drawable.camera);
        
        MenuItem item2 = menu.add(0, 1, 0, R.string.item2);
        item2.setIcon(R.drawable.dial);
        
        MenuItem item3 = menu.add(0, 1, 0, R.string.item3);
        item3.setIcon(R.drawable.sms);
        
        return super.onCreateOptionsMenu(menu);
    }
 
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) 
    {
        // TODO Auto-generated method stub
        return super.onPrepareOptionsMenu(menu);
    }
    
    //enable为true时,菜单添加图标有效,enable为false时无效。4.0系统默认无效
    private void setIconEnable(Menu menu, boolean enable)
    {
        try 
        {
            Class<?> clazz = Class.forName("com.android.internal.view.menu.MenuBuilder");
            Method m = clazz.getDeclaredMethod("setOptionalIconsVisible", boolean.class);
            m.setAccessible(true);
            
            //MenuBuilder实现Menu接口,创建菜单时,传进来的menu其实就是MenuBuilder对象(java的多态特征)
            m.invoke(menu, enable);
            
        } catch (Exception e) 
        {
            e.printStackTrace();
        }
    }
}


Xamarin.Android Code:

using Android.App;
using Android.Views;
using Android.OS;
using Android.Support.V7.App;
using Android.Widget;
using Toolbar = Android.Support.V7.Widget.Toolbar;
using Android.Media;
using Android.Runtime;

namespace HelloToolbar
{
    [Activity(Label = "Support v7 Toolbar", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : MyBaseActivity
    {

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.main);

            var toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);

            //Toolbar will now take on default actionbar characteristics
            SetSupportActionBar(toolbar);

            SupportActionBar.Title = "Hello from Appcompat Toolbar";


            var toolbarBottom = FindViewById<Toolbar>(Resource.Id.toolbar_bottom);

            toolbarBottom.Title = "Photo Editing";
            toolbarBottom.InflateMenu(Resource.Menu.photo_edit);
            toolbarBottom.MenuItemClick += (sender, e) => {
                Toast.MakeText(this, "Bottom toolbar pressed: " + e.Item.TitleFormatted, ToastLength.Short).Show();
            };

            FindViewById<ImageView>(Resource.Id.image).Click += (sender, e) => {
                //StartActivity(typeof(CanvasActivity));
            };

        }

        /// <Docs>The options menu in which you place your items.</Docs>
        /// <returns>To be added.</returns>
        /// <summary>
        /// This is the menu for the Toolbar/Action Bar to use
        /// </summary>
        /// <param name="menu">Menu.</param>
        public override bool OnCreateOptionsMenu (IMenu menu)
        {
            MenuInflater.Inflate (Resource.Menu.home, menu);
            return base.OnCreateOptionsMenu (menu);
        }

        public override bool OnOptionsItemSelected (IMenuItem item)
        {   
            Toast.MakeText(this, "Top ActionBar pressed: " + item.TitleFormatted, ToastLength.Short).Show();
            return base.OnOptionsItemSelected (item);
        }

        public override bool OnMenuOpened(int featureId, IMenu menu)
        {
            System.Diagnostics.Debug.WriteLine(featureId);
            if (menu != null)
            {
                var javaObj = (Java.Lang.Object)menu;
                var javaClass = javaObj.Class;
                if (javaClass.SimpleName.EndsWith("MenuBuilder"))
                {
                    try
                    {
                        Java.Lang.Reflect.Method m = javaClass.GetDeclaredMethod("setOptionalIconsVisible", new Java.Lang.Class[] { Java.Lang.Boolean.Type });
                        m.Accessible = true;
                        m.Invoke(javaObj, new Java.Lang.Object[] { true });
                    }
                    catch (Java.Lang.NoSuchFieldException e)
                    {
                        System.Console.WriteLine("onMenuOpened:{0}", e.ToString());
                    }
                }
            }
            return base.OnMenuOpened(featureId, menu);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值