带有嵌套片段的ViewPager?

时间:2013-09-24 09:37:05

标签: android android-fragments nested android-viewpager fragmentpageradapter

我的问题

根据Google的文档:

  

您现在可以在片段中嵌入片段。这对于a非常有用   您希望放置动态和可重复使用的各种情况   UI组件成为一个自身动态的UI组件   可重复使用。例如,如果您使用ViewPager创建的片段    向左和向右滑动并消耗大部分屏幕空间    现在可以将片段插入到每个片段页面中。要嵌套片段,   只需在你所在的Fragment上调用getChildFragmentManager()   想要添加一个片段。这将返回您可以使用的FragmentManager   像往常一样使用顶层活动来创建   片段交易。例如,这里添加了一些代码   片段来自现有的Fragment类:

Fragment videoFragment = new VideoPlayerFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.video_fragment, videoFragment).commit();

所以我创建了自己的PageFragment。我的PageFragmentAdapter由3页PageFragment组成。 我还有六个片段:Fragment1Fragment2Fragment3FragmentAFragmentBFragmentC。 在我的MainActivity我初始化了我的六个片段,我的ViewPager及其PageFragmentAdapter(为自己初始化了三个PageFragment

然后我使用此方法将Fragment1Fragment2Fragment3附加到PageFragment的每个页面(每个PageFragmentAdapter):

PageFragmentAdapter tPageFragmentAdapter = new PageFragmentAdapter(getSupportFragmentManager());
tPageFragmentAdapter.setFirstPage(tFragment1);
tPageFragmentAdapter.setSecondPage(tFragment2);
tPageFragmentAdapter.setThirdPage(tFragment3);

我可以回复(通过PageFragmentAdapter中的方法)片段并将“嵌套片段”放入我的PageFragment(当然在onCreate()中),如:

getChildFragmentManager().beginTransaction()
.add(R.id.framelayout_history, mFragment)
.addToBackStack(null)
.commit();

注意:我使用PageFragment.setNestedFragment()在其中设置mFragment

它很棒! 它将帮助我(但这个故事不是关于它)简单地替换ViewPager中的片段,如:

tPageFragmentAdapter.replaceFirstPage(tFragmentA);

但我有一个很大的问题。 再次谷歌的文档:

  

PagerAdapter的实现,将每个页面表示为片段   只要用户,它就一直保存在片段管理器中   可以返回页面。此版本的寻呼机最适合在何时使用   有一些通常更多的静态片段要被分页   通过,例如一组标签。 用户每页的片段    访问将保留在内存中,但其视图层次结构可能    在不可见时被销毁。这可能会导致使用重要内容   因为片段实例可以保持任意的内存量   国家数量。

正如您所看到的,PageFragmentAdapter可以销毁我的PageFragment,当然还有它的嵌套片段。当它将被重新创建时,它将具有NULL而不是mFragment值。 我想通过getChildFragmentManager().putFragment()保存它,然后通过getChildFragmentManager().getFragment()获取它。但它没有用。

问题

所以我的问题是:如何在我的父片段中保存我的嵌套片段?有可能吗?

我非常感谢你的帮助。亚历克斯。附:真的很抱歉我的英语:)

修改

Thx @AndroidBegin.com的答案!

  

这似乎是新添加的嵌套支持中的一个错误   片段。基本上,子FragmentManager最终会破碎   与活动分离时的内部状态。短期的   为我修复它的解决方法是将以下内容添加到onDetach()   您调用getChildFragmentManager()的每个片段:

@Override
public void onDetach() {
    super.onDetach();

    try {
        Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
        childFragmentManager.setAccessible(true);
        childFragmentManager.set(this, null);

    } catch (NoSuchFieldException e) {
        throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}

2 个答案:

答案 0 :(得分:12)

在你的片段上试试这个。

public class Fragment2 extends SherlockFragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.viewpager_main, container, false);
        // Locate the ViewPager in viewpager_main.xml
        ViewPager mViewPager = (ViewPager) view.findViewById(R.id.viewPager);
        // Set the ViewPagerAdapter into ViewPager
        mViewPager.setAdapter(new ViewPagerAdapter(getChildFragmentManager()));
        return view;
    }

    @Override
    public void onDetach() {
        super.onDetach();
        try {
            Field childFragmentManager = Fragment.class
                    .getDeclaredField("mChildFragmentManager");
            childFragmentManager.setAccessible(true);
            childFragmentManager.set(this, null);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}

来源:http://www.androidbegin.com/tutorial/actionbarsherlock-side-menu-navigation-nested-viewpager-fragment-tabs-tutorial/

答案 1 :(得分:0)

没有理由进行任何概述的黑客攻击。如果您使用的是ViewPager和PagerAdapter(不确定在提出问题时是否存在),则可以使用FragmentPagerAdapter为您管理可滑动选项卡的片段。

class MyFragmentPagerAdapter(
  private val context: Context,
  fragmentManager: FragmentManager
) : FragmentPagerAdapter(fragmentManager) {
  override fun getCount() = 2

  override fun getItem(position: Int) = when(position) {
    0 -> FirstFragment()
    1 -> SecondFragment()
    else -> throw IllegalStateException("Unexpected position $position")
  }

  override fun getPageTitle(position: Int): CharSequence = when(position) {
    0 -> context.getString(R.string.first)
    1 -> context.getString(R.string.second)
    else -> throw IllegalStateException("Unexpected position $position")
  }
}

还有

class ParentFragment: Fragment() {
  override fun onCreateView(...) = ...

  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    viewPager.adapter = MyFragmentPagerAdapter(requireContext(), childFragmentManager)
    tabLayout.setupWithViewPager(viewPager)
  }
}