2015-12-21 94 views
2

我在我的應用程序中有選項卡。每個選項卡具有不同的片段並具有不同的菜單。下面是我在onCreate()使用Viewpager與不同的菜單和常用工具欄不工作

<?xml version="1.0" encoding="utf-8"?> 
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:id="@+id/drawer_layout" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <android.support.design.widget.CoordinatorLayout 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"> 

     <android.support.design.widget.AppBarLayout 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:background="@color/background"> 

      <include 
       layout="@layout/toolbar" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       app:layout_scrollFlags="scroll|enterAlways" /> 


     </android.support.design.widget.AppBarLayout> 

     <com.CustomViewPager 
      android:id="@+id/view_pager" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" 
      app:layout_behavior="@string/appbar_scrolling_view_behavior" /> 

     <android.support.design.widget.TabLayout 
      android:id="@+id/tab_layout" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:layout_gravity="end" 
      android:background="@color/background" 
      app:layout_anchor="@id/view_pager" 
      app:layout_anchorGravity="bottom|center_horizontal" 
      app:layout_behavior="com.widget.ScrollTabBehavior" 
      app:tabBackground="@color/background" 
      app:tabIndicatorColor="@color/toolbar" 
      app:tabIndicatorHeight="0dp" 
      app:tabMode="fixed" 
      app:tabPaddingEnd="0dp" 
      app:tabPaddingStart="0dp" /> 

    </android.support.design.widget.CoordinatorLayout> 

    <RelativeLayout 
     android:id="@+id/left_drawer" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:layout_gravity="start" 
     android:layout_marginLeft="-64dp" 
     android:layout_marginStart="-64dp" 
     android:background="@color/toolbar" 
     android:choiceMode="singleChoice" 
     android:divider="@android:color/transparent" 
     android:dividerHeight="0dp"> 

     <ImageButton 
      android:id="@+id/close_btn" 
      android:layout_width="50dp" 
      android:layout_height="50dp" 
      android:layout_alignParentEnd="true" 
      android:layout_alignParentRight="true" 
      android:layout_alignParentTop="true" 
      android:background="@android:color/transparent" 
      android:padding="5dp" 
      android:src="@drawable/close_icon" /> 

     <view 
      android:id="@+id/drawerlist" 
      class="android.support.v7.widget.RecyclerView" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:layout_below="@+id/close_btn" /> 

    </RelativeLayout> 
</android.support.v4.widget.DrawerLayout> 

現在與每一個片段我還進一步提到setHasOptionsMenu(true);佈局。我已經覆蓋了onCreateOptionsMenu()中的每個片段,其中有menu.clear();,然後調用它的超級構造函數,然後膨脹片段自己的菜單xml。但我得到的結果是這樣的 -

  • 假設有5個選項卡。第二和第三個選項卡viewpager內的每個
  • 1選項卡中包含兩個片段沒有菜單
  • 第二個選項卡menu_2(僅適用於第2子片段)
  • 第三個標籤再沒有菜單
  • 第四標籤有menu_4(僅適用於第一個子片段)
  • 第5個選項卡有menu_5
  • 最初,應該沒有選項卡1的菜單,沒關係。然後直接轉到第三個標籤,它會顯示menu_4,默認情況下應該不顯示菜單。然後滑動到標籤4,它將顯示適當的menu_4,然後滑回到第3個標籤,它將不顯示菜單(這是根據需要)。
  • 這同樣的事情發生在選項卡5上。如果我切換到第二個選項卡中的第二個孩子片段,那麼在第一個選項卡中會觀察到相同的行爲。

簡而言之,根據我的觀察,它顯示了在當前片段之後實際得到執行的相鄰選項卡的菜單,因此發生了這種行爲。

那麼如何避免這種情況呢?

回答

13

我寫了一個小測試應用程序來檢查行爲。

enter image description here

讓我們通過樣本和看到的,如果出錯了片段(正如你看到的上面,ViewPager有不同的菜單就像一個魅力)

Activity的XML:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <android.support.design.widget.TabLayout 
     android:id="@+id/tabLayout" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content"/> 

    <android.support.v4.view.ViewPager 
     android:id="@+id/viewPager" 
     android:layout_below="@+id/tabLayout" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"/> 
</RelativeLayout> 

Activity class。重要的部分是invalidateOptionsMenu()每次ViewPager都有PageSelected事件。然後,我們將setHasOptionsMenu設置爲所有片段,並將子片段(從嵌套ViewPager s)設置爲false,如果它們超出屏幕的話。

public class MainActivity extends AppCompatActivity { 

    PagerAdapter pagerAdapter; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     Fragment[] fragments = { 
       Fragment.instantiate(this, FragmentNoMenu.class.getName()), 
       Fragment.instantiate(this, FragmentA.class.getName()), 
       Fragment.instantiate(this, FragmentNoMenu.class.getName()), 
       Fragment.instantiate(this, FragmentB.class.getName()), 
     }; 

     TabLayout tabLayout = (TabLayout)findViewById(R.id.tabLayout); 
     ViewPager viewPager = (ViewPager)findViewById(R.id.viewPager); 
     pagerAdapter = new PagerAdapter(getSupportFragmentManager(), fragments); 
     viewPager.setAdapter(pagerAdapter); 
     viewPager.setOffscreenPageLimit(0); 
     viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 
      @Override 
      public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} 
      @Override 
      public void onPageSelected(int position) { 
       invalidateOptionsMenu(position); 
      } 
      @Override 
      public void onPageScrollStateChanged(int state) {} 
     }); 

     invalidateOptionsMenu(0); 
     tabLayout.setupWithViewPager(viewPager); 
    } 

    private void invalidateOptionsMenu(int position) { 
     for(int i = 0; i < pagerAdapter.getCount(); i++) { 
      Fragment fragment = pagerAdapter.getItem(i); 
      fragment.setHasOptionsMenu(i == position); 

      if (fragment instanceof FragmentWithViewPager) { 
       FragmentWithViewPager fragmentWithViewPager = (FragmentWithViewPager)fragment; 
       if (fragmentWithViewPager.pagerAdapter != null) { 
        for (int j = 0; j < fragmentWithViewPager.pagerAdapter.getCount(); j++) { 
         fragmentWithViewPager.pagerAdapter.getItem(j).setHasOptionsMenu(i == position); 
        } 
       } 
      } 
     } 

     invalidateOptionsMenu(); 
    } 
} 

PagerAdapter類:我使用

public class PagerAdapter extends FragmentPagerAdapter { 

    private final Fragment[] fragments; 

    public PagerAdapter(FragmentManager fragmentManager, Fragment[] fragments) { 
     super(fragmentManager); 
     this.fragments = fragments; 
    } 

    @Override 
    public CharSequence getPageTitle(int position) { 
     return fragments[position].getClass().getSimpleName(); 
    } 

    @Override 
    public Fragment getItem(int position) { 
     return fragments[position]; 
    } 

    @Override 
    public int getCount() { 
     return fragments.length; 
    } 
} 

我這裏還有我的測試片段:

FragmentNoMenu類:

public class FragmentNoMenu extends android.support.v4.app.Fragment { 

    @Nullable 
    @Override 
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 
     return inflater.inflate(R.layout.fragment_no_menu, container, false); 
    } 
} 

FragmentNoMenu佈局:

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:background="#0F0F50" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"/> 

FragmentA類是嵌套ViewPager片段:

public class FragmentA extends FragmentWithViewPager { 

    @Nullable 
    @Override 
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 
     View rootView = inflater.inflate(R.layout.fragment_a, container, false); 

     Fragment[] fragments = { 
       Fragment.instantiate(getContext(), SubFragmentA.class.getName()), 
       Fragment.instantiate(getContext(), SubFragmentB.class.getName()), 
       Fragment.instantiate(getContext(), SubFragmentC.class.getName()), 
     }; 

     if (pagerAdapter == null) { 
      pagerAdapter = new PagerAdapter(getChildFragmentManager(), fragments); 
     } 

     viewPager = (ViewPager)rootView.findViewById(R.id.viewPager); 
     viewPager.setAdapter(pagerAdapter); 
     return rootView; 
    } 

    @Override 
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
     inflater.inflate(R.menu.fragment_a, menu); 
     super.onCreateOptionsMenu(menu, inflater); 
    } 
} 

FragmentA的佈局:

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:background="#B0B0B0" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 
    <android.support.v4.view.ViewPager 
     android:id="@+id/viewPager" 
     android:layout_marginTop="80dp" 
     android:layout_width="match_parent" 
     android:layout_height="200dp"/> 
</FrameLayout> 

FragmentA的菜單:

<?xml version="1.0" encoding="utf-8"?> 
<menu xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto"> 
    <item 
     android:id="@+id/action_item_1" 
     android:title="Item 1" 
     android:orderInCategory="250" 
     app:showAsAction="never" /> 

    <item 
     android:id="@+id/action_item_2" 
     android:title="Item 2" 
     android:orderInCategory="300" 
     app:showAsAction="never" /> 
</menu> 

NB! FragmentA擴展FragmentWithViewPager - 它是Fragment小的擴展,使其更容易區分嵌套片段片段在MainActivity:

public class FragmentWithViewPager extends Fragment { 
    PagerAdapter pagerAdapter; 
    ViewPager viewPager; 
} 

FragmentB

public class FragmentB extends Fragment { 

    @Nullable 
    @Override 
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 
     return inflater.inflate(R.layout.fragment_b, container, false); 
    } 

    @Override 
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
     inflater.inflate(R.menu.fragment_b, menu); 
     super.onCreateOptionsMenu(menu, inflater); 
    } 
} 

它的佈局&菜單:

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:background="#999999" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"/> 

..... 

<?xml version="1.0" encoding="utf-8"?> 
<menu xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto"> 
    <item 
     android:id="@+id/action_item3" 
     android:title="Item 3" 
     android:icon="@drawable/ic_triage_star" 
     android:orderInCategory="250" 
     app:showAsAction="always" /> 
</menu> 

子片段(從代碼角度看它們都是相同的):

佈局:

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:background="#AA0000" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <TextView 
     android:text="SubFragment C (with icon Menu)" 
     android:textSize="24sp" 
     android:textColor="#00BB00" 
     android:gravity="center" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"/> 

</FrameLayout> 

代碼:

public class SubFragmentB extends Fragment { 

    @Nullable 
    @Override 
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 
     return inflater.inflate(R.layout.subfragment_b, container, false); 
    } 
} 

這就是它!我已將項目上傳到我的保管箱 - feel free to check it out

我希望,它有助於

+0

這是我的工作代碼...問題是viewpager內viewpager ... –

+0

@JimitPatel現在我看到這個問題。幸運的是,它是可以修復的:想法是爲所有片段和子片段設置HaseOptionsMenu,每次ViewPager改變它的頁面時,這些片段和子片段都會出現在屏幕&invalidateOptionsMenu之外。我已更新我的代碼,文件,預覽圖像。一探究竟! –

+0

將嘗試很酷 –