具有不同菜单和常用工具栏的 Viewpager 不起作用 [英] Viewpager with different menu and common toolbar not working

查看:12
本文介绍了具有不同菜单和常用工具栏的 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">

让我们看一下示例,看看您的片段是否有问题(如上所示,具有不同菜单的 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">

Activity 类.重要的部分是 invalidateOptionsMenu() 每次 ViewPager 有 PageSelected 事件.然后,我们将 setHasOptionsMenu 设置为所有片段,并将 subfragments(来自嵌套的 ViewPagers)设置为 false屏幕.

公共类 MainActivity 扩展 AppCompatActivity {分页适配器分页适配器;@覆盖protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);片段 [] 片段 = {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(), 片段);viewPager.setAdapter(pagerAdapter);viewPager.setOffscreenPageLimit(0);viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {@覆盖public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}@覆盖公共无效 onPageSelected(int position) {无效选项菜单(位置);}@覆盖公共无效 onPageScrollStateChanged(int state) {}});无效选项菜单(0);tabLayout.setupWithViewPager(viewPager);}私人无效invalidateOptionsMenu(int位置){for(int i = 0; i < pagerAdapter.getCount(); i++) {片段片段 = pagerAdapter.getItem(i);fragment.setHasOptionsMenu(i == 位置);如果(片段实例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);}}}}无效选项菜单();}}

PagerAdapter 类:

公共类 PagerAdapter 扩展 FragmentPagerAdapter {私有最终片段 [] 片段;公共 PagerAdapter(FragmentManager fragmentManager, Fragment[] 片段) {超级(片段管理器);this.fragments = 片段;}@覆盖公共 CharSequence getPageTitle(int position) {返回片段[位置].getClass().getSimpleName();}@覆盖公共片段getItem(int位置){返回片段[位置];}@覆盖公共 int getCount() {返回片段.长度;}}

这是我使用的测试片段:

FragmentNoMenu 类:

public class FragmentNoMenu 扩展 android.support.v4.app.Fragment {@Nullable@覆盖public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup 容器, @Nullable Bundle savedInstanceState) {返回inflater.inflate(R.layout.fragment_no_menu,容器,假);}}

FragmentNoMenu 布局:

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

FragmentA 类是一个带有嵌套 ViewPager 的 Fragment:

公共类 FragmentA 扩展 FragmentWithViewPager {@Nullable@覆盖public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup 容器, @Nullable Bundle savedInstanceState) {查看 rootView = inflater.inflate(R.layout.fragment_a, container, false);片段 [] 片段 = {Fragment.instantiate(getContext(), SubFragmentA.class.getName()),Fragment.instantiate(getContext(), SubFragmentB.class.getName()),Fragment.instantiate(getContext(), SubFragmentC.class.getName()),};如果(pagerAdapter == null){pagerAdapter = new PagerAdapter(getChildFragmentManager(), 片段);}viewPager = (ViewPager)rootView.findViewById(R.id.viewPager);viewPager.setAdapter(pagerAdapter);返回根视图;}@覆盖public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {inflater.inflate(R.menu.fragment_a,菜单);super.onCreateOptionsMenu(menu, inflater);}}

FragmentA的布局:

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"安卓:背景=#B0B0B0"android:layout_width="match_parent"android:layout_height="match_parent">

FragmentA的菜单:

<?xml version="1.0" encoding="utf-8"?><菜单 xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"><项目android:id="@+id/action_item_1"android:title="项目 1"机器人:orderInCategory="250"应用程序:showAsAction="从不"/><项目android:id="@+id/action_item_2"android:title="项目 2"机器人:orderInCategory="300"应用程序:showAsAction="从不"/></菜单>

注意!FragmentA 扩展了 FragmentWithViewPager - 它是 Fragment 的一个小扩展,以便更容易在 MainActivity 中区分带有嵌套片段的片段:

公共类 FragmentWithViewPager 扩展 Fragment {分页适配器分页适配器;视图页面视图页面;}

片段B:

公共类 FragmentB 扩展 Fragment {@Nullable@覆盖public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup 容器, @Nullable Bundle savedInstanceState) {返回inflater.inflate(R.layout.fragment_b,容器,假);}@覆盖public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {inflater.inflate(R.menu.fragment_b,菜单);super.onCreateOptionsMenu(menu, inflater);}}

这是布局&菜单:

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"安卓:背景=#999999"android:layout_width="match_parent"android:layout_height="match_parent"/>......<?xml 版本="1.0" 编码="utf-8"?><菜单 xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"><项目android:id="@+id/action_item3"android:title="第 3 项"android:icon="@drawable/ic_triage_star"机器人:orderInCategory="250"应用程序:showAsAction="总是"/></菜单>

子片段(从代码的角度来看,它们看起来都一样):

布局:

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"安卓:背景=#AA0000"android:layout_width="match_parent"android:layout_height="match_parent"><文本视图android:text="SubFragment C (带图标菜单)"安卓:textSize="24sp"安卓:textColor="#00BB00"机器人:重力=中心"android:layout_width="match_parent"android:layout_height="match_parent"/></框架布局>

代码:

公共类 SubFragmentB 扩展 Fragment {@Nullable@覆盖public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup 容器, @Nullable Bundle savedInstanceState) {返回inflater.inflate(R.layout.subfragment_b,容器,假);}}

就是这样!我已将项目上传到我的保管箱 - 随时查看

希望对你有帮助

I have tabs in my app. Each tab is of different fragments and has different menu. Below is the layout which I am using

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

Now with every Fragment in onCreate() I have mentioned setHasOptionsMenu(true); further more. I have overriden the function onCreateOptionsMenu() in each fragment which has menu.clear(); at first then calling it's super constructor then inflating fragment's own menu xml. But result I am getting is something like this -

  • Suppose there are 5 tabs. 2nd and 3rd tab has viewpager within each consist of two more fragments within
  • 1st tab has no menu
  • 2nd tab has menu_2 (only for 2nd child fragment)
  • 3rd tab again has no menu
  • 4th tab has menu_4 (only for 1st child fragment)
  • 5th tab has menu_5
  • Initially, there should be no menu for tab 1 which is ok. Then moving to 3rd tab directly it shows menu_4 which by default should show no menu. Then sliding to tab 4, it will show proper menu_4 then sliding back to 3rd tab it will show no menu (which is as required).
  • This same thing happens for tab 5. If I am switching to 2nd child fragment within 2nd tab then the same behavior is observed with 1st tab.

In short, according to my observation it is showing the menu of adjacent tabs which is actually getting executed after the current fragment and therefore such behavior is occurring.

So how to avoid this?

解决方案

I have written small test-application to check the behaviour.

Let's go through the sample and see, if something wrong with your fragments (as you see above, ViewPager with different menus works like a charm)

Activity's 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. Important part is invalidateOptionsMenu() every time ViewPager has PageSelected event. Then, we setting setHasOptionsMenu to all fragments and subfragments(from the nested ViewPagers) to false if they out of screen.

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

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

Here're my test fragments I used:

FragmentNoMenu class:

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

<?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 class is a Fragment with nested 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's layout:

<?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's menu:

<?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 extends FragmentWithViewPager - it's a small extension of Fragment to make it easier to distinguish Fragments with nested fragments in 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);
    }
}

It's layout & menu:

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

Subfragments (they are all look the same from the code perspective):

Layouts:

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

Code:

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

That's it! I've uploaded the project to my dropbox - feel free to check it out!

I hope, it helps

这篇关于具有不同菜单和常用工具栏的 Viewpager 不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆