Skip to content Skip to sidebar Skip to footer

How Do I Dynamically Add And Remove Fragment Pages Using Viewpager2 And Mediator Tab Layout

I need to add fragments to viewpager2 as well as tabs at runtime depending on server config file. Most viewpager2 resources I have seen showcase a static viewpager2 using the new T

Solution 1:

This is how you implement it in Kotlin

viewPager = binding.viewPagerContainer
        val tabLayout : TabLayout = binding.tabLayout

        val fragmentList : MutableList<Pair<String, Fragment>> = mutableListOf()
        fragmentList.add(Pair(getString(R.string.assets), AssetFragment.newInstance()))
        fragmentList.add(Pair(getString(R.string.news), NewsFragment.newInstance()))

        val adapter = AppFragmentAdapter(fragmentList, this)

        Handler(Looper.myLooper()!!).postDelayed({
            adapter.addFragment(Pair(getString(R.string.videos), VideosFragment.newInstance()))
        }, 1000)

        Handler(Looper.myLooper()!!).postDelayed({
            adapter.removeFragment(2)
        }, 2000)

        viewPager.adapter = adapter
        viewPager.offscreenPageLimit = 2val layoutInflater : LayoutInflater = LayoutInflater.from(context)

        viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {

            overridefunonPageSelected(position: Int) {
                super.onPageSelected(position)
                val actionBar : ActionBar = (requireActivity() as AppCompatActivity).supportActionBar!!
                actionBar.title = adapter.getFragmentName(position)
            }

        })

        TabLayoutMediator(tabLayout, viewPager){ tab, position ->
            tab.customView = prepareTabView(layoutInflater, tabLayout, adapter.getFragmentName(position), tabIcons[position])
        }.attach()

Here we already tested to add and remove the last fragment using some basic delay upon launching an Activity or Parent Fragment. You can create a custom view for each tab or just use tab.text = "Tab Name" for simplicity.

Now the type of adapter you will be using with ViewPager2 for Fragment is FragmentStateAdapter

classAppFragmentAdapter(privateval fragmentList: MutableList<Pair<String, Fragment>>, fragment: Fragment) : FragmentStateAdapter(fragment) {

//    private var pageIds = fragmentList.map { fragmentList.hashCode().toLong() }overridefungetItemCount(): Int = fragmentList.size

    overridefuncreateFragment(position: Int): Fragment {
        return fragmentList[position].second
    }

//    override fun getItemId(position: Int): Long = pageIds[position] // Make sure notifyDataSetChanged() works//    override fun containsItem(itemId: Long): Boolean = pageIds.contains(itemId)fungetFragmentName(position: Int) = fragmentList[position].first

    funaddFragment(fragment: Pair<String, Fragment>) {
        fragmentList.add(fragment)
        notifyDataSetChanged()
    }

    funremoveFragment(position: Int) {
        fragmentList.removeAt(position)
        notifyDataSetChanged()
    }

}

If your structure is Parent Fragment > ViewPager2 > Child Fragments the above code will work fine.

If your structure is Activity > ViewPager2 > Fragments just change

classAppFragmentAdapter(privateval fragmentList: MutableList<Pair<String, Fragment>>, fragment: Fragment) : FragmentStateAdapter(fragment)

to

classAppFragmentAdapter(privateval fragmentList: MutableList<Pair<String, Fragment>>, fragment: FragmentActivity) : FragmentStateAdapter(fragment)

then instead of

val adapter = AppFragmentAdapter(fragmentList, this)

pass the Fragment's activity like this

valadapter= AppFragmentAdapter(fragmentList, requireActivity())

Internally FragmentStateAdapter(fragment) from our adapter already handle which FragmentManager is supposedly use.

Activity > ViewPager2 > Fragments

publicFragmentStateAdapter(@NonNull FragmentActivity fragmentActivity) {
    this(fragmentActivity.getSupportFragmentManager(), fragmentActivity.getLifecycle());
}

Parent Fragment > ViewPager2 > Child Fragments

publicFragmentStateAdapter(@NonNull Fragment fragment) {
    this(fragment.getChildFragmentManager(), fragment.getLifecycle());
}

I was deceived first by searching in SO about dynamically add/remove Fragment with ViewPager2 before trying the simplest approach I could come up.

Post a Comment for "How Do I Dynamically Add And Remove Fragment Pages Using Viewpager2 And Mediator Tab Layout"