美文网首页Xamarin
Xamarin.Android Menu 添加 Icon 无效问

Xamarin.Android Menu 添加 Icon 无效问

作者: Xamarin信仰中心 | 来源:发表于2018-10-05 14:07 被阅读20次

    问题分析

    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);
            }
        }
    }
    

    相关文章

      网友评论

        本文标题:Xamarin.Android Menu 添加 Icon 无效问

        本文链接:https://www.haomeiwen.com/subject/gcofaftx.html