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

带有嵌套片段的ViewPager?

奚和光
2023-03-14

根据谷歌的文档:

现在可以在片段中嵌入片段。这对于各种情况都很有用,在这些情况下,您需要将动态和可重用的UI组件放置到本身是动态和可重用的UI组件中。例如,如果使用ViewPager创建左右滑动并占用大部分屏幕空间的片段,现在可以将片段插入每个片段页面。要嵌套片段,只需对要添加片段的片段调用getChildFragmentManager()。这将返回一个FragmentManager,您可以像通常从顶级活动中一样使用它来创建片段事务。例如,下面是一些从现有片段类中添加片段的代码:

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

所以我创建了自己的页面片段。我的PageFragmentAdapter由3页组成。我还有六个片段:Fragment1Fragment2Fragment3FragmentAFragmentBFragmentC。在我的主活动中,我初始化了我的六个片段,我的查看页面和它的页面片段适配器(它为自己初始化了三个页面片段)。

然后,我使用此方法将我的片段1、片段2、片段3连接到页面片段适配器的每个页面(每个页面片段):

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

我可以(通过PageFragmentAdapter中的方法)Fragments并将“嵌套片段”制作到我的Page片段中(当然在onCreate()中),例如:

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

注意:我使用PageFragment.setNestedFrament()在其中设置m片段

而且效果很好!简单地替换ViewPager中的片段将有助于我(但本故事不是关于它的),例如:

tPageFragmentAdapter.replaceFirstPage(tFragmentA);

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

PagerAdapter的实现,将每个页面表示为一个片段,只要用户可以返回该页面,该片段就会持久保存在片段管理器中。这个版本的寻呼机最适合在有少量通常更静态的片段需要分页时使用,例如一组选项卡。用户访问的每个页面的片段将保留在内存中,尽管其视图层次结构在不可见时可能会被破坏。这可能会导致使用大量内存,因为片段实例可以保持任意数量的状态。

如您所见,PageFragmentAdapter可以销毁每个my的页面片段,当然还有它的嵌套片段。当它被重新创建时,它将有一个NULL值,而不是mFragment。我试图通过getChildFragmentManager()保存它。putFragment(),然后通过getChildFragmentManager()获取它。getFragment()。但它不起作用。

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

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

Thx@AndroidBegin。com寻求答案!

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

@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个答案

郑卜鹰
2023-03-14

没有理由做任何概述的黑客行为。如果您使用的是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)
  }
}
戴博
2023-03-14

在你的碎片上试试这个。

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

资料来源:https://www.swipetips.com/actionbarsherlock-side-menu-navigation-nested-viewpager-fragment-tabs-tutorial/

 类似资料:
  • 我正在编写一个应用程序,它有一个导航抽屉,并且使用嵌套片段。导航抽屉几乎是按照Android文档创建的——它可以工作。我希望导航抽屉始终可见,这就是为什么我有一个活动,我只是交换片段。其中一个片段是ViewPager,它又有自己的片段作为页面。 导航是这样分层的: 其中片段是,子片段是它的页面。当我刚从抽屉转到时,所有内容都正常工作,但我不知道如何直接切换到给定页面(嵌套片段)。 处理导航抽屉点击

  • 在我的应用程序中,一个

  • Back Stack是否支持与Android中的嵌套片段交互? 如果是这样,我做错了什么?在我的实现中,后退按钮完全忽略了我将此事务添加到后堆栈的事实。我希望这不是因为嵌套片段的问题,只是我做了一些不正确的事情。 以下代码位于我的一个片段中,用于将新片段与当前显示的任何嵌套片段交换:

  • 问题内容: 这是我在elasticsearch中存储在索引上的数据类型。我必须找到包含主要成分牛肉(且重量小于1000)和成分-(辣椒粉且重量小于250),(橄榄油和重量小于300)以及所有其他成分类似的食谱。 索引的映射是 我的查询是 但这给了Null。有人可以帮我吗?我认为我没有正确使用嵌套查询 问题答案: 试试这个:

  • 我有一个嵌套片段的项目(https://github.com/checklist/NestedFragmentsRecycler)。FragmentA位于MainActivity中,包含带有适配器的RecyclerView。适配器中的每个项目都将返回FragmentB。因为我需要给一个id来装载FragmentB到位置,并且它需要是唯一的,所以我正在生成我自己的id。第一个片段显示得很好,但不幸的

  • 问题内容: 我实现了带有ViewPager和TabsAdapter的ActionBarSherlock。它运作良好,但是现在我试图从另一个表中的“标签1”中加载的框架中“推送”。 该行为应类似于: 我的应用程序中有3个选项卡,启动时会看到第一个选项卡,其中有一个带有按钮的片段 按下第一个选项卡上的按钮,应替换第一个选项卡上的片段,并显示另一个片段 我试图实现这一点,但是在更换时有一个黑色的片段。