Get current fragment with ViewPager2

与世无争的帅哥 提交于 2020-04-07 17:42:32

问题


I'm migrating my ViewPager to ViewPager2 since the latter is supposed to solve all the problems of the former. Unfortunately, when using it with a FragmentStateAdapter, I don't find any way to get the currently displayed fragment.

viewPager.getCurrentItem() gives the current displayed index and adapter.getItem(index) generally creates a new Fragment for the current index. Unless keeping a reference to all created fragments in getItem(), I have no idea how to access the currently displayed fragment.

With the old ViewPager, one solution was to call adapter.instantiateItem(index) which would return the fragment at the desired index.

Am I missing something with ViewPager2?


回答1:


I had similar problem when migrating to ViewPager2.

In my case I decided to use parentFragment property (I think you can make it also work for activity) and hope, that ViewPager2 will keep only the current fragment resumed. (i.e. page fragment that was resumed last is the current one.)

So in my main fragment (HostFragment) that contains ViewPager2 view I created following property:

private var _currentPage: WeakReference<MyPageFragment>? = null
val currentPage
    get() = _currentPage?.get()

fun setCurrentPage(page: MyPageFragment) {
    _currentPage = WeakReference(page)
}

I decided to use WeakReference, so I don't leak inactive Fragment instances

And each of my fragments that I display inside ViewPager2 inherits from common super class MyPageFragment. This class is responsible for registering its instance with host fragment in onResume:

override fun onResume() {
    super.onResume()
    (parentFragment as HostFragment).setCurrentPage(this)
}

I also used this class to define common interface of paged fragments:

abstract fun someOperation1()

abstract fun someOperation2()

And then I can call them from the HostFragment like this:

currentPage?.someOperation1()

I'm not saying it's a nice solution, but I think it's more elegant than relying on internals of ViewPager's adapter with instantiateItem method that we had to use before.




回答2:


I was able to get access to current fragment in FragmentStateAdapter using reflection.

Extension function in Kotlin:

fun FragmentStateAdapter.getItem(position: Int): Fragment? {
    return this::class.superclasses.find { it == FragmentStateAdapter::class }
        ?.java?.getDeclaredField("mFragments")
        ?.let { field ->
            field.isAccessible = true
            val mFragments = field.get(this) as LongSparseArray<Fragment>
            return@let mFragments[getItemId(position)]
        }
}

Add Kotlin reflection dependency if needed:

implementation "org.jetbrains.kotlin:kotlin-reflect:1.3.61"

Example call:

val tabsAdapter = viewpager.adapter as FragmentStateAdapter
val currentFragment = tabsAdapter.getItem(viewpager.currentItem)



回答3:


The ViewPagerAdapter is intended to hide all these implementation details which is why there is no straight-forward way to do it.

You could try setting and id or tag on the fragment when you instantiate it in getItem() then use fragmentManager.findFragmentById() or fragmentManager.findFragmentByTag() to retrieve.

Doing it like this, however, is a bit of a code smell. It suggests to me that stuff is being done in the activity when it should be done in the fragment (or elsewhere).

Perhaps there is another approach to achieve what you want but it's hard to give suggestions without knowing why you need to get the current fragment.




回答4:


supportFragmentManager.findFragmentByTag("f" + viewpager.currentItem)

with FragmentStateAdapter in placeFragmentInViewHolder(@NonNull final FragmentViewHolder holder)add Fragment

mFragmentManager.beginTransaction()
                    .add(fragment, "f" + holder.getItemId())
                    .setMaxLifecycle(fragment, STARTED)
                    .commitNow()



回答5:


I also had your problem and used this trick

    Map<Integer, Fragment> map = new HashMap<>();

@Override
        public Fragment createFragment(int position) {
            Fragment fragment;
            switch (position) {
                case 0:
                    fragment = new CircularFragment();
                    map.put(0, fragment);
                    return fragment;
                case 1:
                    fragment = new LocalFragment();
                    map.put(1, fragment);
                    return fragment;
                case 2:
                    fragment = new SettingsFragment();
                    map.put(2, fragment);
                    return fragment;
            }
            fragment = new CircularFragment();
            map.put(0, fragment);
            return fragment;
        }

and you can get fragment like this

 LocalFragment f = (LocalFragment) map.get(1);



回答6:


was facing same issue now its solved by adding one object in adapter

class MyViewPager2Adapter(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) {


    private val FRAGMENTS_SIZE = 2

    var currentFragmentWeakReference: WeakReference<Fragment>? = null

    override fun getItemCount(): Int {
        return this.FRAGMENTS_SIZE
    }

    override fun createFragment(position: Int): Fragment {

        when (position) {
            0 -> {
                currentFragmentWeakReference= MyFirstFragment()
                return MyFirstFragment()
            }
            1 -> {
                currentFragmentWeakReference= MySecondFragment()
                return MySecondFragment()
            }
        }

        return MyFirstFragment() /for default view

    }

}

after creating adapter I registered my Viewpager 2 with ViewPager2.OnPageChangeCallback() and overrided its method onPageSelected

now simple did this trick to get current fragment

 private fun getCurrentFragment() :Fragment?{

        val fragment = (binding!!.pager.adapter as MyViewPager2Adapter).currentFragmentWeakReference?.get()

        retrun fragment
    }

I've only tested this with 2 fragments in ViewPager2

cheers guys , hope this mayhelp you.!



来源:https://stackoverflow.com/questions/55728719/get-current-fragment-with-viewpager2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!