当前位置: 首页 > 知识库问答 >
问题:

Android ViewPager与标签不保持状态后屏幕旋转

孔磊
2023-03-14

我正在实现一个与谷歌在这里提供的实现类似的选项卡的ViewPager。

我的应用程序具有以下行为。我的ViewPager有3个“页面”(fragA、fragB、fragC),我正在ViewPager顶部实现3个选项卡。谷歌的实现和我的不同之处在于,这些标签不用于在片段之间导航。例如,按下我的一个选项卡,在可见片段上加载一组不同的数据。我可以让fragA选择tab3,fragB选择tab2,fragC选择tab1。

问题是当我旋转屏幕时。如果我在FragmentA上选择了第三个选项卡,当我旋转屏幕时,我会停留在同一个片段中,但现在选择了第一个选项卡。我希望在旋转屏幕时保持选中的相同选项卡。

这是我管理选项卡的类:

public class ManagerTabs extends Fragment {

    private TabHost.TabContentFactory mFactory = new TabHost.TabContentFactory() {

        @Override
        public View createTabContent(String tag) {
            View v = new View(getActivity());
            v.setMinimumWidth(0);
            v.setMinimumHeight(0);
            return v;
        }
    };

    public static ManagerTabs newManager() {
        return new ManagerTabs();
    }


    @Override
    public View onCreateView(LayoutInflater inflater,  ViewGroup container,
     Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.datatabs, container, false);
        createTabs();
        createPager();
        return view;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        if (savedInstanceState != null) {
            currentPage = savedInstanceState.getInt("currentPage", currentPage);
            currentTab = savedInstanceState.getInt("currentTab", currentTab);
            mTabHost.setCurrentTab(currentTab);
        }
        mPager.setCurrentItem(currentPage);
    }

    private void createPager() {
        mPager = (ViewPager) view.findViewById(R.id.datapager);
        pagerAdapter = new PagerAdapter(getChildFragmentManager());
        mPager.setAdapter(pagerAdapter);

        IconPageIndicator indicator = (IconPageIndicator) rootView.findViewById(R.id.indicator);
        indicator.setViewPager(pager);
        indicator.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                currentTab = mTabHost.getCurrentTab();

                currentPage = mPager.getCurrentItem();

                switch (currentPage) {
                case 0:
                    ((FragmentA) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab);
                    break;
                case 1:
                    ((FragmentB) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab);
                    break;
                case 2:
                    ((FragmentC) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab);
                    break;
                }
            }
        });
    }

    private void createTabs() {

        mTabHost = (TabHost) view.findViewById(android.R.id.tabhost);
        mTabHost.setup();

        mTabHost.addTab(mTabHost.newTabSpec(getString(R.string.day))setIndicator(getString(R.string.day)).setContent(mFactory));
        mTabHost.addTab(mTabHost.newTabSpec(getString(R.string.month)).setIndicator(getString(R.string.month)).setContent(mFactory));
        mTabHost.addTab(mTabHost.newTabSpec(getString(R.string.year)).setIndicator(getString(R.string.year)).setContent(mFactory));

        mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
            public void onTabChanged(String tag) {
                currentTab = mTabHost.getCurrentTab();
                currentPage = mPager.getCurrentItem();
                switch (currentPage) {
                case 0:
                    ((FragmentA) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab);
                    break;
                case 1:
                    ((FragmentB) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab);
                    break;
                case 2:
                    ((FragmentC) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab);
                    break;
                }
            }
        });
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("currentPage", mPager.getCurrentItem());
        outState.putInt("currentTab", mTabHost.getCurrentTab());
    }
}

这是创建片段的适配器:

public class PagerAdapter extends FragmentPagerAdapter implements IconPagerAdapter{

    private Fragment[] currentFragment = new Fragment[3];

    public PagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int index) {
        Fragment fragment;
        switch (index) {
        case 0:
            fragment = FragmentA.newInstance();
            break;
        case 1:
            fragment = FragmentB.newInstance();
            break;
        case 2:
            fragment = FragmentC.newInstance();
            break;
        default:
            fragment = null;
            break;
        }

        currentFragment[index] = fragment;

        return fragment;
    }

    @Override
    public int getIconResId(int index) {

        switch (index) {
        case 0:
            return R.drawable.fraga;
        case 1:
            return R.drawable.fragb;
        case 2:
            return R.drawable.fragc;
        default:
            return -1;
        }
    }

    @Override
    public int getCount() {
        return 3;
    }

    public Fragment getCurrentFragment(int currentFrag) {
        return currentFragment[currentFrag];
    }

    public Fragment[] getCurrentFragment() {
        return currentFragment;
    }
}

最后,片段(片段a、片段B和片段C)几乎相同:

public class FragmentA extends Fragment {

    public static FragmentA newInstance() {
        return new FragmentA();
    }

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

        mTabHost = (TabHost) ((View) container.getParent().getParent()).findViewById(android.R.id.tabhost);

        if (savedInstanceState != null) {
            currentTab = savedInstanceState.getInt("currentTab");
        }
        populateLayout(currentTab);

        return rootView;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("currentTab", currentTab);
    }
}

问题是所有myonCreateView总是被调用两次,第二次调用时,信息丢失。我已经调试并看到了这种行为,

当我转屏时,例如在FragmentA中,选择了第三个选项卡,会发生这种情况:

01  ManagerTabs -> onSaveInstanceState
02  FragmentA -> onSaveInstanceState
03  ManagerTabs -> onCreateView
04  ManagerTabs -> onViewCreated

在04调用中(managertab-

如果我转屏,我可以做什么来保持当前选择的选项卡?

共有1个答案

万俟玉书
2023-03-14

屏幕旋转后,将创建FragmentPagerAdapter的新实例。但是ViewPager会恢复其状态以及它包含的所有片段的状态ViewPager不调用适配器getView()方法。因此,Fragment[]currentFragment仅包含null值。

您可以通过其他方式获得当前片段。

如果使用FragmentPagerAdapter

FragmentPagerAdapter在传递给FragmentManager的片段上设置标记。此id取决于页面索引。您可以在最新支持库的源代码中看到该id的生成方式。

要实现这一点,只需将以下方法添加到managerTables片段中:

public Fragment getCurrentPagerFragment(int position) {
    String fragmentTag = "android:switcher:" + mPager.getId() + ":" + position;
    return getChildFragmentManager().findFragmentByTag(fragmentTag);
}

如果使用FragmentStatePagerAdapter

它不会在碎片上设置标签。使用FragmentStatePagerAdapter,我们似乎可以通过使用它的instantiateItem(ViewGroup容器,int位置)调用。它返回位置位置的片段引用。如果FragmentStatePagerAdapter已经持有对有问题的片段的引用,instantiateItem只返回对该片段的引用,并且不调用getItem()来再次实例化它。在这种情况下,我们的方法将是:

public Fragment getCurrentPagerFragment(int position) {
    FragmentStatePagerAdapter a = (FragmentStatePagerAdapter) mPager.getAdapter();
    return (Fragment) a.instantiateItem(pager, position);
}

最后:

现在使用上述方法获取当前片段。就你而言:

mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
    public void onTabChanged(String tag) {
        currentTab = mTabHost.getCurrentTab();
        currentPage = mPager.getCurrentItem();
        Fragment currentFragment = getCurrentPagerFragment(currentPage);
        switch (currentPage) {
            case 0:
                ((FragmentA) currentFragment).getData(currentTab);
                break;
            case 1:
                ((FragmentB) currentFragment).getData(currentTab);
                break;
            case 2:
                ((FragmentC) currentFragment).getData(currentTab);
                break;
        }
    }
});
 类似资料:
  • 在屏幕旋转后,虽然我在super.onCreate(null);,中传递null,但我得到了object返回的nullPointerException异常。我知道在传递savedInstanceState=null的同时必须销毁并重新创建活动,这意味着活动应该在旋转后开始,因为它是第一次开始,为什么在旋转后会出现此异常? onCreate()代码段,其中名为historyText的对象 Logca

  • HTTP协议是无状态的:每次请求都是一次新的请求,不会记得之前通信的状态 客户端与服务器端的一次通信,就是一次会话 实现状态保持的方式:在客户端或服务器端存储与会话有关的数据 存储方式包括cookie、session,会话一般指session对象 使用cookie,所有数据存储在客户端,注意不要存储敏感信息 推荐使用sesison方式,所有数据存储在服务器端,在客户端cookie中存储sessio

  • 问题内容: 在我公司,我们正在将Web应用程序的前端迁移到ReactJS。我们正在使用create-react- app(更新为v16),而没有Redux。现在,我停留在一个页面上,该页面可以通过以下图像进行简化: 在MainContainer方法中,使用相同的后端请求检索由三个组件(SearchableList,SelectableList和Map)显示的数据。然后,此请求的结果存储在MainC

  • 实现在竖屏的NavigationController中push一个横屏的UIViewController,模拟器测试兼容5.0、6.0系统。实现程序中手动旋转屏幕的效果。 [Code4App.com]

  • 函数名称:保持屏幕常亮 函数功能:保持屏幕常亮 函数方法 device.wake() 函数用例 device.keepWake() 注意事项 目前积木编程函数和触动精灵函数不通用,请仔细查看本手册,此手册中函数仅支持积木编程,不支持触动精灵,同理请勿将触动精灵函数在积木编程运行。

  • 我正在为我的列表使用滑动列表视图库。列表适配器正在使用视图持有者模式,一切正常。我设置向左轻扫,列表项视图下有一个后退视图。在这个后视图上,我有一个文本视图“删除”。单击后,正在执行删除操作。适配器中的数据正在刷新。行已删除 。但是“滑动状态”被设置在位置靠近删除的那一行的行上。我不相信它发生,因为转换视图记住了“滑动状态”。当我注释掉检查转换视图是否为空时,问题消失了,但列表滚动性能是不可接受的