在ViewPager2中启动子片段

6

我正在使用ViewPager2FragmentStateAdapter,基本上有3个片段(A-B-C),这意味着你可以从A滚动到B,从B滚动到C。

我的想法是什么?

从片段B开始启动子片段D

(A-B-C) | D 从片段B开始启动片段D,当用户点击“返回箭头”(顶部栏)时,片段D将被销毁,用户将返回B。(我不想使用活动)

我尝试过什么?

val ft: FragmentTransaction = requireActivity().supportFragmentManager.beginTransaction()
ft.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out)
ft.replace(android.R.id.content, DetailsFragment())
ft.addToBackStack(null)
ft.commit();

我用上面的代码遇到了两个问题。

  1. 两个片段(B 和创建的 D)重叠(我同时看到了 B 和 D)。
  2. 点击顶部栏上的返回按钮时,既不会关闭片段 B,也不会关闭片段 D。

编辑: 在 onCreate() 方法中将片段管理器传递给 ViewPager2,放在主要活动中。

pagerAdapter = PagerAdapter(supportFragmentManager, lifecycle)
binding.mainViewPager.adapter = pagerAdapter

PagerAdapter是一个简单的类: class PagerAdapter(fm: FragmentManager, lifecycle: Lifecycle) : FragmentStateAdapter(fm, lifecycle)

你在 Fragment 或 Activity 中的哪里初始化 ViewPagerAdapter? - Công Hải
展示一下你传递给适配器的片段管理器。 - Công Hải
@CôngHải 更新了。 - Thomas Banderas
  1. 你应该使用add而不是replace。
  2. 确保为内容视图DetailFragment设置背景。当您设置背景时,它不会重叠。
  3. 当您按下返回按钮的顶部栏时,应该调用哪个方法?您应该调用activity?.onBackPress()。
- Công Hải
这里是我的回答,链接为answer,解决了这个问题。 - Parsamlm
2个回答

3

使用getChildFragmentManager()代替getSupportFragmentManager()


我得到了相同的结果,但是我必须将android.R.id.content更改为R.id.main,这是MasterFragment()(B)的主容器(因为我收到了“在详细片段中找不到android.R.id.content”的错误)。 - Thomas Banderas
这是关于编程的内容,请查看以下链接获取已有的答案:https://dev59.com/PWYr5IYBdhLWcg3wy9SA#13391359 https://dev59.com/PWYr5IYBdhLWcg3wy9SA#13381792 - Krishna Sony
这不是ViewPager v1.0的旧解决方案吗? - Thomas Banderas
因为文档说当您使用版本2.0时,请使用FragmentStateAdapter。 - Thomas Banderas
是的,你是对的。你需要使用监听器将主容器从ViewPager Fragment中替换掉。 - Krishna Sony

1
这是一个关于从ViewPager的片段进入详细片段的答案。
由于我将ViewPager放在了片段中,使得问题变得有些复杂,如果你愿意,可以跳过这一步并将其添加到活动中。
按照以下步骤操作:
1. 为活动创建布局。

<androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">


    <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/appbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:popupTheme="@style/ThemeOverlay.AppCompat.ActionBar" />

    </com.google.android.material.appbar.AppBarLayout>

    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <androidx.fragment.app.FragmentContainerView
                android:id="@+id/fragment_container_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

FragmentContainerView 包含了拥有 ViewPager2 的 fragment。

//  Replace Fragment with DSL style
    supportFragmentManager.commit {
        replace<FragmentThatContainsViewPager>(R.id.fragment_container_view)

    }

包含ViewPager的片段布局
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">

    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

        <com.google.android.material.tabs.TabLayout
                android:id="@+id/tabLayout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:tabMode="scrollable" />

        <androidx.viewpager2.widget.ViewPager2
                android:id="@+id/viewPager"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/tabLayout" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

容器片段的代码

class FragmentThatContainsViewPager : BaseDataBindingFragment<FragmentWithViewpagerBinding>() {

    override fun getLayoutRes(): Int {
        return R.layout.fragment_with_viewpager
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return super.onCreateView(inflater, container, savedInstanceState)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // TabLayout
        val tabLayout = dataBinding.tabLayout
        // ViewPager2
        val viewPager = dataBinding.viewPager

        /*
             Set Adapter for ViewPager inside this fragment using this Fragment,
            more specifically childFragmentManager as param
         */
        viewPager.adapter = ChildFragmentStateAdapter(this)

        // Bind tabs and viewpager
        TabLayoutMediator(tabLayout, viewPager) { tab, position ->
            tab.text = "Tab $position"
        }.attach()

    }

}

ViewPager的适配器,如果你希望我使用 FragmentFactory,你可以使用 GenericFragmentParent.newInstance()。

class ChildFragmentStateAdapter(private val fragment: Fragment) : FragmentStateAdapter(fragment) {

private val genericFragmentFactory = GenericFragmentFactory.getFragmentFactory()


override fun getItemCount(): Int = 5

override fun createFragment(position: Int): Fragment {

    genericFragmentFactory.fragID = position

    return genericFragmentFactory.instantiate(
        fragment.requireActivity().classLoader,
        GenericFragmentParent::class.java.name
    )
}

}

class GenericFragmentParent(private val fragID: Int) :
    BaseDataBindingFragment<FragmentGenericParentBinding>() {


    override fun getLayoutRes(): Int {
        return R.layout.fragment_generic_parent
    }



    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        dataBinding.btnNextPage.setOnClickListener {

            /*
                 Replacing in container in Activity for both fragments to
                be in same stack of supportFragmentManager
             */
            requireActivity().supportFragmentManager.commit {
                replace<GenericChildFragment>(R.id.fragment_container_view)
                    .addToBackStack(null)
            }
        }

    }

}

同时使用后退栈数量来在顶部显示返回箭头。
  supportFragmentManager.addOnBackStackChangedListener {

            val fragmentOnTop = supportFragmentManager.findFragmentById(
                R.id.fragment_container_view
            )

            val fragmentCount = supportFragmentManager.backStackEntryCount

            supportActionBar?.setDisplayHomeAsUpEnabled(fragmentCount > 0)

        }

And

override fun onSupportNavigateUp(): Boolean {
    supportFragmentManager.popBackStack()
    return true
}

当点击返回箭头时删除片段。

我添加了一个示例在这里,它位于MaterialDesign模块中,可能需要为ViewPager选项卡的子片段添加另一个导航示例,每个选项卡都有自己的子片段,而不是打开详细片段,尽管您可以轻松滑动ViewPager2的相邻片段。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接