Android จัดรายการเมนูไปทางซ้ายในแถบการทำงาน

ฉันมีแถบการทำงานในแอปพลิเคชันที่แสดงรายการเมนูที่กำหนดไว้ใน res/menu/activity_main.xml ของฉัน

รายการเมนูของฉันจัดชิดขวาบนแถบการทำงาน ฉันต้องการให้พวกเขาจัดชิดซ้าย

เฉพาะวิธีแก้ปัญหาที่ฉันพบสำหรับแถบการกระทำแบบกำหนดเองที่ใช้แล้ว เช่นนี้: การวางตำแหน่งรายการเมนูทางด้านซ้ายของ ActionBar ใน Honeycomb

อย่างไรก็ตาม ฉันไม่ต้องการสร้างรูปแบบที่กำหนดเองสำหรับเมนูของฉัน ฉันต้องการใช้รายการเมนูเริ่มต้นที่สร้างจาก res/menu/activity_main.xml ของฉัน

เป็นไปได้ไหม?


person hendrix    schedule 17.10.2012    source แหล่งที่มา
comment
คุณอาจต้องการดูแถบการทำงานแยก ผู้ใช้ Android คุ้นเคยกับไอคอน ActionBar ทางด้านขวาหรือบนแถบแยกที่อยู่ด้านล่างของหน้าจอ คุณไม่ต้องการออกแบบสิ่งที่ผู้ใช้ Android คุ้นเคยและสบายใจอยู่แล้ว developer.android.com/guide/topics/ui/actionbar.html# แยกบาร์   -  person Sababado    schedule 17.10.2012
comment
ตรวจสอบโพสต์นี้ มันควรจะช่วยคุณได้ stackoverflow.com/questions/7454102/   -  person pepyakin    schedule 23.10.2012
comment
ฉันไม่ได้รับคะแนนโหวต ฉันหมายถึงคำถามชัดเจนเพียงพอ ถ้าคำตอบคือไม่ นั่นก็ไม่ได้ทำให้คำถามแย่...   -  person hendrix    schedule 21.10.2013
comment
@hendrix สวัสดี .. คุณบรรลุภารกิจนี้ได้อย่างไร .. ฉันมีข้อกำหนดเดียวกัน ..   -  person Prabs    schedule 20.07.2015


คำตอบ (2)


ฉันอยากรู้เกี่ยวกับเรื่องนี้ ดังนั้นฉันจึงขุดลึกลงไปในแหล่งที่มาของ SDK ฉันใช้ AppCompatActivity กับรายการเมนู 3 รายการในไฟล์ XML และฉันใช้วิธี onCreateOptionMenu เริ่มต้น ซึ่งก็คือ:

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

หลังจากที่ฉันเปลี่ยนจากวิธีขยายด้วยดีบักเกอร์แล้ว ฉันได้ดำเนินการตามสแต็กต่อไปนี้:

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)

มันสิ้นสุดด้วยเมธอด updateMenuView ของ BaseMenuPresenter นี่คือจุดที่งานที่เกี่ยวข้องเสร็จสิ้น

รหัสวิธีการ:

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 และรูปแบบที่สูงเกินจริง abc_action_menu_layout.xml

ซึ่งหมายความว่าหากคุณมีมุมมองนี้ คุณสามารถทำสิ่งที่คุณต้องการได้ ตามทฤษฎี ฉันคิดว่ามันสามารถทำได้ด้วยการไตร่ตรองเยอะๆ แต่มันจะเจ็บปวด แทนที่จะทำเช่นนั้น คุณสามารถทำซ้ำได้ในโค้ดของคุณ ดูการใช้งานได้ที่นี่

ตามสิ่งที่กล่าวมาข้างต้น คำตอบสำหรับคำถามของคุณคือ ใช่ สามารถทำได้ แต่จะยุ่งยาก

แก้ไข:

ฉันสร้างข้อพิสูจน์แนวคิดสำหรับการทำเช่นนี้ด้วยการไตร่ตรอง ฉันใช้ com.android.support:appcompat-v7:23.1.0

ฉันได้ลองสิ่งนี้บนโปรแกรมจำลอง (Android 6.0) และบน Zuk Z1 (CM Android 5.1.1) ของฉันแล้วใช้งานได้ดีทั้งคู่

เมนู 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>

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

แม้ว่าแรงโน้มถ่วงจะเปลี่ยนไปที่นี่ แต่บนหน้าจอก็ไม่ได้สร้างความแตกต่างที่ชัดเจนแต่อย่างใด เพื่อให้มองเห็นการเปลี่ยนแปลงได้จริง ควรปรับพารามิเตอร์โครงร่างอื่นๆ (เช่น width )

โดยรวมแล้ว เลย์เอาต์แบบกำหนดเองนั้นใช้งานง่ายกว่ามาก

person csenga    schedule 28.11.2015

คุณสามารถทำได้เช่นนี้:

activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
            ActionBar.DISPLAY_SHOW_CUSTOM);
activity.getActionBar().setCustomView(mAutoSyncSwitch, new ActionBar.LayoutParams(
            ActionBar.LayoutParams.WRAP_CONTENT,
            ActionBar.LayoutParams.WRAP_CONTENT,
            Gravity.CENTER_VERTICAL | Gravity.LEFT));
person user2004181    schedule 23.01.2013
comment
ไม่ใช่เลย์เอาต์ที่กำหนดเอง เขาเพียงเพิ่มพารามิเตอร์เลย์เอาต์ให้กับเลย์เอาต์ที่มีอยู่ เขาไม่เปลี่ยนแปลงอย่างอื่น แต่เพื่อการนั้นเขาจะต้องเขียนเค้าโครงแบบกำหนดเอง เพราะไม่เช่นนั้นเขาจะไม่สามารถแก้ไขเค้าโครงได้ - person Deniz C.; 06.09.2014
comment
แต่ถ้าคุณจำเป็นต้องทำจริงๆ โดยไม่ต้องแก้ไขเค้าโครงของแถบการทำงาน คุณจะไม่สามารถทำได้ - person Deniz C.; 06.09.2014