gui*_*tgl 10 android android-viewpager androidx
我要迁移ViewPager到,ViewPager2因为后者应该可以解决前者的所有问题。不幸的是,当与结合使用时FragmentStateAdapter,我找不到任何方法来获取当前显示的片段。
viewPager.getCurrentItem()给出当前显示的索引,adapter.getItem(index)通常Fragment为当前索引创建一个新索引。除非保留对中所有创建的片段的引用,否则getItem()我不知道如何访问当前显示的片段。
使用old时ViewPager,一种解决方案是调用adapter.instantiateItem(index),它将以所需的索引返回该片段。
我错过了什么ViewPager2吗?
Xen*_*ion 60
ViewPager2默认情况下,在FragmentManager 中为片段分配了标签,如下所示:
第一个位置的片段有一个标签 "f0"
第二个位置的片段有一个标签 "f1"
第三个位置的片段有一个标签"f2"等等......所以你可以获得片段的标签,并通过将“f”与片段的位置连接起来。要获取当前 Fragment,您可以从 viewPager2 位置获取当前位置,并使您的标签像这样(对于 Kotlin):
val myFragment = supportFragmentManager.findFragmentByTag("f" + viewpager.currentItem)
Run Code Online (Sandbox Code Playgroud)
对于某个位置的片段
val myFragment = supportFragmentManager.findFragmentByTag("f" + position)
Run Code Online (Sandbox Code Playgroud)
如果您使用这种技术,您可以投射 Fragment 并始终检查它是否为空。
如果您在 Fragment 中托管您的 ViewPager2,请childFragmentManager改用。
记住
如果你overriden在getItemId(position: Int)你的适配器。那么你的情况就不一样了。它应该是:
val myFragment = supportFragmentManager.findFragmentByTag("f" + your_id_at_that_position)
Run Code Online (Sandbox Code Playgroud)
或者简单地:
val myFragment = supportFragmentManager.findFragmentByTag("f" + adapter.getItemId(position))
Run Code Online (Sandbox Code Playgroud)
如果您在托管的片段ViewPager2,使用childFragmentManager代替supportFragmentManager。
Alm*_*hty 16
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)
}
Run Code Online (Sandbox Code Playgroud)
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)
}
Run Code Online (Sandbox Code Playgroud)
I also used this class to define common interface of paged fragments:
abstract fun someOperation1()
abstract fun someOperation2()
Run Code Online (Sandbox Code Playgroud)
And then I can call them from the HostFragment like this:
currentPage?.someOperation1()
Run Code Online (Sandbox Code Playgroud)
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.
Mic*_*cer 13
通过标签查找当前 Fragment 的解决方案似乎最适合我。我为此创建了这些扩展函数:
fun ViewPager2.findCurrentFragment(fragmentManager: FragmentManager): Fragment? {
return fragmentManager.findFragmentByTag("f$currentItem")
}
fun ViewPager2.findFragmentAtPosition(
fragmentManager: FragmentManager,
position: Int
): Fragment? {
return fragmentManager.findFragmentByTag("f$position")
}
Run Code Online (Sandbox Code Playgroud)
Activity,请使用supportFragmentManager
或fragmentManager。Fragment,请使用childFragmentManager注意:
findFragmentAtPosition仅适用于在 ViewPager2 的 RecyclerView 中初始化的 Fragment。因此,您只能获得可见的位置 + 1。ViewPager2.的fun ViewPager2.findFragmentAtPosition,因为你不使用来自ViewPager2类东西。我认为它应该留在那里,因为此解决方法仅适用于 ViewPager2。我能够使用反射访问 FragmentStateAdapter 中的当前片段。
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)]
}
}
Run Code Online (Sandbox Code Playgroud)
如果需要,添加 Kotlin 反射依赖项:
implementation "org.jetbrains.kotlin:kotlin-reflect:1.3.61"
Run Code Online (Sandbox Code Playgroud)
示例调用:
val tabsAdapter = viewpager.adapter as FragmentStateAdapter
val currentFragment = tabsAdapter.getItem(viewpager.currentItem)
Run Code Online (Sandbox Code Playgroud)
小智 1
ViewPagerAdapter 旨在隐藏所有这些实现细节,这就是为什么没有直接的方法来做到这一点。
当您实例化片段然后getItem()使用fragmentManager.findFragmentById()或fragmentManager.findFragmentByTag()检索时,您可以尝试在片段上设置 id 或标记。
然而,这样做有点代码味道。它向我表明,应该在片段(或其他地方)中完成的事情正在活动中完成。
也许还有另一种方法可以实现您想要的目标,但在不知道为什么需要获取当前片段的情况下很难给出建议。
| 归档时间: |
|
| 查看次数: |
871 次 |
| 最近记录: |