【问题标题】:Start child fragment in ViewPager2在 ViewPager2 中启动子片段
【发布时间】:2020-05-16 10:17:26
【问题描述】:

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

我想做什么?

从片段 B 开始子片段 D

(A-B-C) | D 从fragment B开始fragment D,当用户点击“返回箭头”(顶栏)时,fragment D会被销毁,用户会回到B。(我不想使用activity)

我尝试了什么?

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() 方法的 main_activity 中将片段管理器传递给ViewPager2

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

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

【问题讨论】:

  • 您在片段或活动中在哪里初始化 viewpageradapter?
  • 告诉我你传递给适配器的片段管理器
  • @CôngHải 已更新
  • 1.您应该使用添加而不是替换。 2. 确保为内容视图 DetailFragment 设置背景。当您设置背景时,它不会重叠。 3.按返回键顶栏有什么方法?你应该调用activity?.onBackPress()
  • 这里是answer 我回答这个问题的地方

标签: android android-viewpager android-viewpager2


【解决方案1】:

使用getChildFragmentManager() 代替getSupportFragmentManager()

【讨论】:

  • 我有相同的结果,但我必须将android.R.id.content 更改为R.id.main 这是MasterFragment() (B) 的主要容器(因为我有错误“找不到@987654328 @详细信息片段")
  • 这不是 viewpager v 1.0 的旧解决方案?
  • 因为当你使用 2.0 版时,文档说“使用 FragmentStateAdapter”
  • 是的。你说的对。您需要使用侦听器从 ViewPager 片段中替换主容器。
【解决方案2】:

这是从 ViewPager 的片段中作为问题状态的详细片段的答案。

我还通过将 viewPager 放入片段中使其变得有点复杂,如果您愿意,可以跳过并将其添加到活动中。

  1. 为 Activity 创建布局

<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 的片段

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

    }

FragmentThatContainsViewPager 的布局

<?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(片段) {

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)

        }

还有

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

触摸返回箭头时删除片段。

我添加了示例here,它在 MaterialDesign 模块中,可能为 ViewPager 选项卡的子片段的导航添加了另一个示例,每个子片段都有自己的子片段,而不是打开细节片段 而您可以滑动 ViewPager2 的相邻片段

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多