2015-12-21 100 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

将尝试很酷 –