Android的对齐菜单项来留在操作栏 [英] Android align menu items to left in action bar

查看:130
本文介绍了Android的对齐菜单项来留在操作栏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个显示在定义的菜单项,在我的应用程序操作栏中我的 RES /菜单/ activity_main.xml

i have action bar in my application that displays menu items defined in my res/menu/activity_main.xml

我的菜单项靠右侧的操作栏。我希望他们能够对齐到左。

My menu items are aligned to right on action bar. I want them to be aligned to left.

唯一的解决办法,我发现这个使用的自定义操作栏,像这样的: <一href="http://stackoverflow.com/questions/5306283/positioning-menu-items-to-the-left-of-the-actionbar-in-honeycomb">Positioning菜单项的动作条的左边蜂窝

Only solutions i found for this used custom action bar, like this one: Positioning menu items to the left of the ActionBar in Honeycomb

不过,我不希望创建自定义布局为我的菜单。我想用从我的 RES /菜单/ activity_main.xml生成的默认菜单项

However, i dont want to create custom layout for my menu. I want to use default menu items generated from my res/menu/activity_main.xml.

这可能吗?

推荐答案

嗯,我很好奇这一点,所以我挖很深的SDK源里面。我用 AppCompatActivity 在这3个菜单项的XML文件,我使用的是默认 onCreateOptionMenu 的方法,它是这样的:

Well, i was curious about this, so i dug deep inside the SDK's source. I used AppCompatActivity with 3 menu item in it's XML file, and i used the default onCreateOptionMenu method, which was this:

 @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

在我从充气方法与调试器继续前进,我经历了以下堆栈:

After i move on from the inflate method with the debugger, i went through the following stack:

updateMenuView():96, BaseMenuPresenter (android.support.v7.internal.view.menu)
updateMenuView():231, ActionMenuPresenter (android.support.v7.widget)
dispatchPresenterUpdate():284, MenuBuilder (android.support.v7.internal.view.menu)
onItemsChanged():1030, MenuBuilder (android.support.v7.internal.view.menu)
startDispatchingItemsChanged():1053, MenuBuilder (android.support.v7.internal.view.menu)
preparePanel():1303, AppCompatDelegateImplV7 (android.support.v7.app)
doInvalidatePanelMenu():1541, AppCompatDelegateImplV7 (android.support.v7.app)
access$100():92, AppCompatDelegateImplV7 (android.support.v7.app)
run():130, AppCompatDelegateImplV7$1 (android.support.v7.app)
handleCallback():739, Handler (android.os)
dispatchMessage():95, Handler (android.os)
loop():148, Looper (android.os)
main():5417, ActivityThread (android.app)
invoke():-1, Method (java.lang.reflect)
run():726, ZygoteInit$MethodAndArgsCaller (com.android.internal.os)
main():616, ZygoteInit (com.android.internal.os)

这结束了​​ BaseMenu presenter updateMenuView 的方法,这正是revelant工作完成。

It ended in BaseMenuPresenter's updateMenuView method, this is where the revelant work is done.

该方法的code:

   public void updateMenuView(boolean cleared) {
        final ViewGroup parent = (ViewGroup) mMenuView;
        if (parent == null) return;

        int childIndex = 0;
        if (mMenu != null) {
            mMenu.flagActionItems();
            ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
            final int itemCount = visibleItems.size();
            for (int i = 0; i < itemCount; i++) {
                MenuItemImpl item = visibleItems.get(i);
                if (shouldIncludeItem(childIndex, item)) {
                    final View convertView = parent.getChildAt(childIndex);
                    final MenuItemImpl oldItem = convertView instanceof MenuView.ItemView ?
                            ((MenuView.ItemView) convertView).getItemData() : null;
                    final View itemView = getItemView(item, convertView, parent);
                    if (item != oldItem) {
                        // Don't let old states linger with new data.
                        itemView.setPressed(false);
                        ViewCompat.jumpDrawablesToCurrentState(itemView);
                    }
                    if (itemView != convertView) {
                        addItemView(itemView, childIndex);
                    }
                    childIndex++;
                }
            }
        }

        // Remove leftover views.
        while (childIndex < parent.getChildCount()) {
            if (!filterLeftoverView(parent, childIndex)) {
                childIndex++;
            }
        }
    }

下面的 getItemView addItemView 方法做什么,他们的名字说。第一膨胀的新视图,并且第二它添加到父。更重要的是,在调试器下的父对象进行检查,这是一个 ActionMenuView < /一>,它继承了的LinearLayout 和膨胀的形式<一href="http://grep$c$c.com/file/repository.grep$c$c.com/java/ext/com.google.android/android/4.4_r1/frameworks/support/v7/appcompat/res/layout/abc_action_menu_layout.xml?av=f"相对=nofollow> abc_action_menu_layout.xml

Here the getItemView and the addItemView methods do what their's name say. The first inflate a new view, and the second add it to parent. What is more important, under the debugger the parent object can be checked, it's an ActionMenuView, which inherits from the LinearLayout and inflated form abc_action_menu_layout.xml.

这意味着,如果你能得到这个观点,你可以做你想做的。从理论上讲,我认为它可以大量反射来实现,但会痛苦。 取而代之的是,你可以在code复制它。实现可以发现这里

This means if you can get this view, you can do what you want. Theoretically, i think it can be done with lots of reflection, but it would painful. Instead of that, you can reproduce it in your code. Implementations can be found here.

根据上面的事,你的问题的答案是肯定的,是可以做到的,但是这将是棘手的。

According to the things above, the answer for your question is YES, it can be done, but it will be tricky.

编辑:

我创建了一个概念证明与反思这样做。我使用 com.android.support:appcompat-v7:23.1.0

I created a proof of concept for doing this with reflection. I've used com.android.support:appcompat-v7:23.1.0.

我已经试过这在一个仿真器(安卓6.0),并在我的ZUK Z1(CM安卓5.1.1),在两个工作正常。

I've tried this on an emulator(Android 6.0) and on my Zuk Z1(CM Android 5.1.1), on both it works fine.

菜单XML:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item android:id="@+id/action_settings" android:title="@string/action_settings"
        android:orderInCategory="100" app:showAsAction="always" />
    <item android:id="@+id/action_settings2" android:title="TEST1"
        android:orderInCategory="100" app:showAsAction="always" />
    <item android:id="@+id/action_settings3" android:title="TEST2"
        android:orderInCategory="100" app:showAsAction="always" />
</menu>

Activty XML:

Activty XML:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="New Button"
        android:id="@+id/button"
        android:layout_gravity="center_vertical" />
</LinearLayout>

活动:

public class Main2Activity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //only a linear layout with one button
        setContentView(R.layout.activity_main2);

        Button b = (Button) findViewById(R.id.button);

        // do the whole process for a click, everything is inited so we dont run into NPE
        b.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                AppCompatDelegate delegate = getDelegate();

                Class delegateImpClass = null;
                Field menu = null;
                Method[] methods = null;

                try {

                    //get objects based on the stack trace
                    delegateImpClass = Class.forName("android.support.v7.app.AppCompatDelegateImplV7");

                    //get delegate->mPreparedPanel
                    Field mPreparedPanelField = delegateImpClass.getDeclaredField("mPreparedPanel");
                    mPreparedPanelField.setAccessible(true);
                    Object mPreparedPanelObject = mPreparedPanelField.get(delegate);

                    //get delegate->mPreparedPanel->menu
                    Class PanelFeatureStateClass = Class.forName("android.support.v7.app.AppCompatDelegateImplV7$PanelFeatureState");
                    Field menuField = PanelFeatureStateClass.getDeclaredField("menu");
                    menuField.setAccessible(true);
                    Object menuObjectRaw = menuField.get(mPreparedPanelObject);
                    MenuBuilder menuObject = (MenuBuilder) menuObjectRaw;

                    //get delegate->mPreparedPanel->menu->mPresenter(0)
                    Field mPresentersField = menuObject.getClass().getDeclaredField("mPresenters");
                    mPresentersField.setAccessible(true);
                    CopyOnWriteArrayList<WeakReference<MenuPresenter>> mPresenters = (CopyOnWriteArrayList<WeakReference<MenuPresenter>>) mPresentersField.get(menuObject);
                    ActionMenuPresenter presenter0 = (ActionMenuPresenter) mPresenters.get(0).get();

                    //get the view from the presenter
                    Field mMenuViewField = presenter0.getClass().getSuperclass().getDeclaredField("mMenuView");
                    mMenuViewField.setAccessible(true);
                    MenuView menuView = (MenuView) mMenuViewField.get(presenter0);
                    ViewGroup menuViewParentObject = (ViewGroup) ((View) menuView);

                    //check the menu items count
                    int a = menuViewParentObject.getChildCount();
                    Log.i("ChildNum", a + "");




                    //set params as you want
                    Toolbar.LayoutParams params = (Toolbar.LayoutParams) menuViewParentObject.getLayoutParams();

                    params.gravity = Gravity.LEFT;

                    menuViewParentObject.setLayoutParams(params);




                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        });
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }
}

虽然重力这里已经改变时,在屏幕上,这并不作任何revelant差异。要获得真正的明显变化等布局PARAMS(如宽度)应进行调整。

Although the gravity has been changed here, on the screen this does not make any revelant difference. To get a real visible change other layout params(e.g. width ) should be tuned.

所有的一切,一个自定义的布局更容易使用。

All in all, a custom layout is much easier to use.

这篇关于Android的对齐菜单项来留在操作栏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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