2012-10-17 34 views
11

tôi có thanh hành động trong ứng dụng của tôi hiển thị các mục menu theo quy định tại res/menu/activity_main.xmlAndroid mục menu class sang trái trong thanh hành động

mục menu My của tôi được liên kết sang phải trên thanh hành động. Tôi muốn chúng được căn chỉnh sang trái.

Chỉ giải pháp tôi tìm thấy cho thanh hành động tùy chỉnh sử dụng này, như thế này: Positioning menu items to the left of the ActionBar in Honeycomb

Tuy nhiên, tôi không muốn tạo bố trí tùy chỉnh cho trình đơn của tôi. Tôi muốn sử dụng các mục menu mặc định được tạo từ res/menu/activity_main.xml của tôi.

Điều này có khả thi không?

+4

Bạn có thể muốn xem thanh Hành động tách. Người dùng Android quen thuộc với các biểu tượng ActionBar ở bên phải hoặc trên thanh phân tách nằm ở cuối màn hình. Bạn không muốn thiết kế lại thứ gì đó mà người dùng Android đã quen thuộc và thoải mái. http://developer.android.com/guide/topics/ui/actionbar.html#SplitBar – Sababado

+1

Kiểm tra bài đăng này. Nó sẽ giúp bạn. http://stackoverflow.com/questions/7454102/how-to-align-items-in-action-bar-to-the-left – pepyakin

+0

Tôi không nhận được downvotes. Tôi có nghĩa là câu hỏi là đủ rõ ràng, nếu câu trả lời là KHÔNG, điều đó không làm cho câu hỏi xấu ... – hendrix

Trả lời

0

Bạn có thể làm điều đó như thế này:

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)); 
+11

Tôi specificaly (bold font) nói tôi không muốn hiển thị xem tùy chỉnh trong thanh hành động ... – hendrix

+0

Nó không phải là một bố trí tùy chỉnh, ông chỉ cần thêm một tham số bố trí để bố trí hiện tại, ông không thay đổi cái gì khác. Nhưng cho rằng anh ta phải viết bố trí tùy chỉnh bởi vì nếu không anh ta sẽ không thể chỉnh sửa bố cục. –

+2

Nhưng nếu bạn thực sự cần phải làm điều đó mà không có bất kỳ chỉnh sửa bố trí hành động, sau đó bạn sẽ không thể làm điều đó. –

3

Vâng, tôi đã tò mò về vấn đề này, vì vậy tôi đào sâu bên trong mã nguồn của SDK. Tôi đã từng AppCompatActivity với mục 3 menu trong tập tin XML của nó, và tôi sử dụng phương pháp mặc định onCreateOptionMenu, mà là thế này:

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

Sau khi tôi chuyển từ phương pháp bung ra với một trình gỡ lỗi, tôi đã trải qua ngăn xếp như sau:

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) 

Nó kết thúc vào updateMenuView phương pháp BaseMenuPresenter 's, đây là nơi mà công việc Revelant được thực hiện.

mã của phương pháp:

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

Ở đây getItemViewaddItemView phương pháp làm những gì tên của họ nói. Lần đầu tiên thổi phồng một chế độ xem mới và thứ hai thêm nó vào cấp độ gốc. Điều quan trọng hơn, dưới trình gỡ lỗi đối tượng cha mẹ có thể được kiểm tra, đó là một ActionMenuView, được kế thừa từ LinearLayout và dạng tăng cao abc_action_menu_layout.xml.

Điều này có nghĩa là nếu bạn có thể có được chế độ xem này, bạn có thể làm những gì bạn muốn. Về mặt lý thuyết, tôi nghĩ rằng nó có thể được thực hiện với rất nhiều sự phản ánh, nhưng nó sẽ gây đau đớn. Thay vì đó, bạn có thể tái tạo nó trong mã của bạn. Việc triển khai có thể được tìm thấy here.

Theo những điều trên, câu trả lời cho câu hỏi của bạn là CÓ, nó có thể được thực hiện, nhưng nó sẽ khó khăn.

Edit:

Tôi tạo ra một bằng chứng của khái niệm để làm điều này với sự phản ánh. Tôi đã sử dụng com.android.support:appcompat-v7:23.1.0.

Tôi đã thử tính năng này trên trình mô phỏng (Android 6.0) và trên Zuk Z1 (CM Android 5.1.1), trên cả hai đều hoạt động tốt.

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

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

Hoạt động:

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

Mặc dù mức độ nghiêm trọng đã được thay đổi ở đây, trên màn hình này không thực hiện bất kỳ Revelant Sự khác biệt. Để có được thay đổi hiển thị thực sự, các thông số bố cục khác (ví dụ: chiều rộng) cần được điều chỉnh.

Tất cả trong tất cả, bố cục tùy chỉnh dễ sử dụng hơn nhiều.

Các vấn đề liên quan