Как добавить еще один фрагмент в ViewPager2?

#android #kotlin #android-fragments #android-viewpager2

Вопрос:

Я пытаюсь динамически добавлять больше фрагментов в свой ViewPager2, однако, когда я вызываю adapter.add(MyNewFragment, position) 2 вещи, происходит, если я использую notifyDataSetChange() не отображается фрагмент, но если я помещаю notifyItemInserted(position) отображается, но приложение вылетает с java.lang.IllegalStateException: Fragment already added .

Это мой класс адаптера:

 class ViewPagerAdapter(
    list: MutableList<Fragment>,
    fm: FragmentManager,
    lifecycle: Lifecycle,
    //fragmentActivity: FragmentActivity
) : FragmentStateAdapter(fm, lifecycle) {

    var fragmentList = list

    override fun getItemCount(): Int {
        return fragmentList.size
    }

    fun addScreen(fragment: Fragment, position: Int) {
        if(!fragmentList.contains(fragment)){
            fragmentList.add(position, fragment)
            //notifyItemInserted(position)
            notifyDataSetChanged()
        }

    }

    override fun createFragment(position: Int): Fragment {
        return fragmentList[position]
    }


    // I tried to use these methods that I saw here but then the viewpager is totally blank and does not load anything or do the same Fragment already added error.

   /* override fun getItemId(position: Int): Long {
        return fragmentList[position].id.toLong()
    }

    override fun containsItem(itemId: Long): Boolean = fragmentList.any { it.id.toLong() == itemId }*/
}
 

А это мой экран, на котором находится видоискатель:

 @AndroidEntryPoint
class ViewPagerScreen : Fragment() {

    //...


    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        if (!::savedViewInstance.isInitialized) {
            _binding = FragmentViewPagerScreenBinding.inflate(inflater, container, false)

            //....
            savedViewInstance = binding.root
        }

        binding.viewPager.isSaveEnabled = false

        return savedViewInstance
    }


    fun addNewScreen(){
        adapter.addScreen(NewFragment(), binding.viewPager.currentItem   1)
    }

    private fun initViewPager() {
        binding.viewPager.offscreenPageLimit = 2
        binding.viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
            override fun onPageScrolled(
                position: Int,
                positionOffset: Float,
                positionOffsetPixels: Int
            ) {
                super.onPageScrolled(position, positionOffset, positionOffsetPixels)
            }
        })

        adapter = ViewPagerAdapterByFragments(
            mutableListOf(FirstScreen(), SecondScreen(), ThirdScreen()),
            this@ViewPagerScreen.childFragmentManager,
            lifecycle
        )
        binding.viewPager.adapter = adapter

        binding.viewPager.isUserInputEnabled = false
    }
}

 

Комментарии:

1. внутри createFragment метода вы не создаете НОВЫЙ фрагмент, вы предоставляете существующий из массива. попробуйте написать этот метод правильно, создайте новый фрагмент в этом методе прямо

2. Большое спасибо!! Теперь это работает как заклинание 😀

Ответ №1:

Я думаю, что решил проблему, спасибо @snachmsm за то, что указал мне, где искать.

То, что я сделал, было довольно просто, мне нужно было только изменить параметр list: MutableList<Fragment> на list:MutableList<Pair<String,Fragment>> String «мой fragmentId «. Затем по методу createFragment возвращаем новый фрагмент базы на мой fragmentId .

Вот сам код:

 override fun createFragment(position: Int): Fragment {
        return when (fragmentList!![position]!!.first) {
            "firstScreen" -> return FirstScreen()
            "secondScreen" ->return SecondScreen()
            "thirdScreen" ->return ThirdScreen()
            "newScreen" -> return NewScreen()
            else -> AnotherScreen()
        }
    }
 

Также мое addScreenMethod() сейчас выглядит так:

 fun addScreen(newfragment: Pair<String, Fragment>, position: Int) {
        val result = fragmentList.find {
            it.first == newfragment.first
        }
 
        if (result == null) {
            fragmentList.add(position, newfragment)
            notifyItemInserted(position)
        }
}