Android menyelaraskan item menu ke kiri di bilah tindakan

saya memiliki bilah tindakan di aplikasi saya yang menampilkan item menu yang ditentukan di res/menu/activity_main.xml saya

Item menu saya disejajarkan ke kanan pada bilah tindakan. Saya ingin mereka sejajar ke kiri.

Hanya solusi yang saya temukan untuk ini menggunakan bilah tindakan khusus, seperti ini: Memposisikan item menu di sebelah kiri ActionBar di Honeycomb

Namun, saya tidak ingin membuat tata letak khusus untuk menu saya. Saya ingin menggunakan item menu default yang dihasilkan dari res/menu/activity_main.xml.

Apakah ini mungkin?


person hendrix    schedule 17.10.2012    source sumber
comment
Anda mungkin ingin melihat ke dalam bilah tindakan Split. Pengguna Android sudah familiar dengan ikon ActionBar di sebelah kanan, atau pada bilah terpisah yang ada di bagian bawah layar. Anda tentu tidak ingin mendesain ulang sesuatu yang sudah familiar dan nyaman bagi pengguna Android. developer.android.com/guide/topics/ui/actionbar.html# Bilah Terpisah   -  person Sababado    schedule 17.10.2012
comment
Periksa posting ini. Ini akan membantu Anda. stackoverflow.com/questions/7454102/   -  person pepyakin    schedule 23.10.2012
comment
Saya tidak mendapatkan suara negatifnya. Maksud saya pertanyaannya sudah cukup jelas, jika jawabannya TIDAK, itu tidak membuat pertanyaan menjadi buruk...   -  person hendrix    schedule 21.10.2013
comment
@hendrix halo..Bagaimana Anda mencapai tugas ini..Saya memiliki persyaratan yang sama..   -  person Prabs    schedule 20.07.2015


Jawaban (2)


Ya, saya penasaran dengan hal ini, jadi saya menggali jauh ke dalam sumber SDK. Saya menggunakan AppCompatActivity dengan 3 item menu di file XML-nya, dan saya menggunakan metode onCreateOptionMenu default, yaitu ini:

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

Setelah saya beralih dari metode inflate dengan debugger, saya melewati tumpukan berikut:

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)

Itu berakhir dengan metode updateMenuView BaseMenuPresenter, di sinilah pekerjaan yang menarik dilakukan.

kode metodenya:

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

Di sini metode getItemView dan addItemView melakukan apa yang tertulis dalam namanya. Yang pertama mengembangkan tampilan baru, dan yang kedua menambahkannya ke induk. Yang lebih penting, di bawah debugger objek induk dapat diperiksa, itu adalah ActionMenuView, yang mewarisi dari LinearLayout dan bentuk yang digelembungkan abc_action_menu_layout.xml.

Artinya jika Anda bisa mendapatkan tampilan ini, Anda bisa melakukan apa yang Anda inginkan. Secara teoritis, menurut saya hal itu bisa dilakukan dengan banyak refleksi, tapi akan menyakitkan. Daripada itu, Anda dapat mereproduksinya dalam kode Anda. Implementasinya dapat ditemukan di sini.

Berdasarkan hal-hal di atas, jawaban atas pertanyaan Anda adalah YA, bisa saja, namun akan tricky.

Sunting:

Saya membuat bukti konsep untuk melakukan ini dengan refleksi. Saya telah menggunakan com.android.support:appcompat-v7:23.1.0.

Saya sudah mencobanya di emulator (Android 6.0) dan di Zuk Z1 saya (CM Android 5.1.1), keduanya berfungsi dengan baik.

XML Menu:

<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 Aktivitas:

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

Aktivitas:

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

Meskipun gravitasi telah diubah di sini, pada layar hal ini tidak membuat perbedaan besar. Untuk mendapatkan perubahan nyata yang terlihat, parameter tata letak lainnya (misalnya lebar ) harus disesuaikan.

Secara keseluruhan, tata letak khusus lebih mudah digunakan.

person csenga    schedule 28.11.2015

Anda dapat melakukannya seperti ini:

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
Ini bukan custom layout, dia hanya menambahkan parameter layout ke layout yang sudah ada, dia tidak mengubah apa pun. Namun untuk itu dia harus menulis custom layout karena jika tidak, dia tidak akan bisa mengedit layout tersebut. - person Deniz C.; 06.09.2014
comment
Namun jika Anda benar-benar perlu melakukannya tanpa mengedit tata letak bilah tindakan, maka Anda tidak akan dapat melakukannya. - person Deniz C.; 06.09.2014