Android ViewPageAdapter,每个标签

时间:2015-08-19 09:01:41

标签: android android-fragments android-viewpager

我有一个Android应用程序,只有一个活动。该活动包含一个带有ViewPageAdapter的SlidingTabLayout,如this示例所示。每个选项卡都包含一个相应的根片段,然后当用户使用该屏幕时,我将其替换为其他片段。视觉表示如下所示:

enter image description here

使用我当前的实现,我执行以下操作:转到tab1,通过将ProductRootFragment替换为ProductListFragment立即加载ProductListFragment。我点击了一个产品,它用ProductDetailFragment替换了ProductListFragment。现在我切换到tab2并通过替换Tab2RootFragment立即加载Tab2ListFragment。我单击一个项目,Tab2DetailFragment替换Tab2ListFragment。我现在返回到Tab1,正如我所料,仍然显示ProductDetailFragment。但是,如果我现在单击后退按钮,它不会像我期望的那样将我带回到ProductListFragment。相反,它会从Backstack中弹出Tab2DetailFragment。

我想为每个“tab”片段实现一个单独的backstack。有几个关于这个的帖子,但它们似乎都已经过时,有些人提出了非常精细的解决方案。 (请参阅hereherehere ...)

似乎在最新版本的SDK中,Android可以自动处理这种backstack层次结构,而不需要在我更换片段的事务中使用getChildFragmentManager而不是getSupportFragmentManager来手动实现某种类型的backstack。但是,我无法让它发挥作用。 (我直觉地认为正确的解决方案就是让Android处理这个问题,因为感觉就像手动覆盖后退按钮并实现自己的堆栈一样精心设计。)

有人可以解释如何正确实现为每个标签维护单独的反向堆栈的预期行为吗?或者可能链接到一个简单,精心设计和最新的如何实现所需行为的示例?

有关我的代码的其他信息: 在我的MainActivity.java中,我使用getSupportFragmentManager()构造了ViewPagerAdapter。

ViewPagerAdapter.java

@Override
public Fragment getItem(int position) {
    switch(position){
        case 0: return new ProductRootFragment();
        ...
    }
    ...
}

ProductRootFragment.java

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

    FragmentTransaction transaction = getFragmentManager()
            .beginTransaction();
    transaction.replace(R.id.product_root_container, new ProductListFragment());
    transaction.commit();
    return view;
}

ProductListFragment.java

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View layout = inflater.inflate(R.layout.product_list_fragment, container, false);
    view = (ProductListView) layout;
    return view;
}
...
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
    ...
    ProductDetailFragment newFragment = new ProductDetailFragment();
    FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(R.id.product_root_container, newFragment);
    transaction.addToBackStack(null);
    transaction.commit();
}

ProductDetailFragment.java

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

3 个答案:

答案 0 :(得分:2)

我知道很晚才回答这个问题,但也许有人仍然需要它。 为实现此目的,您必须在根片段中使用getChildFragmentManager()而不是getFragmentManager()

例如,我有一个ViewPager和TabLayout的活动,我添加 RootFragment1RootFragment2到ViewPager并使用ViewPager设置TabLayout。 现在在我的RootFragment1中替换我的Tab1Fragment1我使用此代码:

final FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.replace(R.id.RootFrame1, Tab1Fragment1.newInstance(), "MyTag");
ft.commit();

需要从backstack弹出片段的方法喜欢这个:

public boolean popBackStack() {
    if(getChildFragmentManager().getBackStackEntryCount() > 0) {
        getChildFragmentManager().popBackStackImmediate();
        return true;
    } else
        return false;
}

例如,我在Tab1Fragment1中有一个按钮,用当前替换片段Tab1Fragment2。 onClickListener按钮必须看起来像这样:

button1.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        final FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.replace(R.id.RootFrame1, Tab1Fragment2.newInstance(), "MyTag");
        ft.addToBackStack(null);
        ft.commit();
    }
});

我对第二个片段(RootFragment2)也这样做。

之后,现在我只需覆盖以下onBackPressed()MainActivity的{​​{1}}个:

@Override
public void onBackPressed() {
    if (viewPager.getCurrentItem() == 0) {
        RootFragment1 fragment = ((RootFragment1) sectionsPagerAdapter.getItem(0));
        if (!fragment.popBackStack())
            super.onBackPressed();
    } else if (viewPager.getCurrentItem() == 1) {
        RootFragment2 fragment = ((RootFragment2) sectionsPagerAdapter.getItem(1));
        if (!fragment.popBackStack())
            super.onBackPressed();
    } else
        super.onBackPressed();
}

我检查每个标签是否包含片段然后从其后台弹出,否则调用super.onBackPressed()进行默认操作。

答案 1 :(得分:0)

您遇到此问题是因为每次更换片段时都会将该片段添加到后台堆栈中。为片段维护的Backstack取决于添加片段的活动。因此,每次执行addToBackStack()时,它都会保持相同的活动。 当您尝试使用场景时,最后添加的片段位于Backstack的顶部,是Tab2DetailFragment。 要解决此问题,每次切换到其他选项卡时都需要清除backstack。 记住你需要清除背斜堆中的所有碎片而不是活动。

答案 2 :(得分:0)

您可以使用以下代码;

@Override
public void onBackPressed() {

    //get current tab index.
    if (viewPager.getCurrentItem() == 1) {
        viewPager.setCurrentItem(0);
    } else if (viewPager.getCurrentItem() == 2) {
        viewPager.setCurrentItem(0);
    } else if (viewPager.getCurrentItem() == 3) {
        viewPager.setCurrentItem(0);
    } else {
        super.onBackPressed();
    }
}