ViewPager2:getPageWidth 替代方案
ViewPager2: getPageWidth alternative
我用 ViewPager2 替换了 ViewPager,但我有问题。
ViewPager 已修复 3 个页面。第二页比其他页大。当第1页或第3页可见时,第2页的一小部分也可见,当第2页可见时,其他页面不可见。为此,我使用了适配器方法
override fun getPageWidth(position: Int): Float {
return if (position != MAIN_PAGE) WIDTH_SMALL_PERCENT
else super.getPageWidth(position)
}
但是 ViewPager2 的适配器没有这个方法,我不知道怎么做。
现在没有黑客是不可能的。我创建功能请求 https://issuetracker.google.com/issues/150232913.
并且在预期功能我创建扩展方法来设置自定义布局管理器
package androidx.viewpager2.widget
import androidx.recyclerview.widget.RecyclerView
import java.lang.reflect.Field
fun ViewPager2.setLayoutManager(layoutManager: RecyclerView.LayoutManager) {
mRecyclerView.layoutManager = layoutManager
mRecyclerView.clearOnChildAttachStateChangeListeners() // to ability set exact view size
setValueToField("mLayoutManager", layoutManager)
mScrollEventAdapter.setValueToField("mLayoutManager", layoutManager) // to correct work ViewPager2.OnPageChangeCallback
}
private fun Any.setValueToField(field: String, value: Any) {
val f1: Field = this.javaClass.getDeclaredField(field)
f1.isAccessible = true
f1.set(this, value)
f1.isAccessible = false
}
并创建自定义 LayoutManager
class WidePageLayoutManager(
private val viewPager: ViewPager2,
private val viewSmallPercentage: Float,
private val smallViewPosition: IntArray
) : LinearLayoutManager(viewPager.context, HORIZONTAL, false) {
// copied from ViewPager2.LinearLayoutManagerImp
override fun calculateExtraLayoutSpace(state: RecyclerView.State, extraLayoutSpace: IntArray) {
val pageLimit: Int = viewPager.offscreenPageLimit
val offscreenSpace: Int = viewPager.pageSize * pageLimit
extraLayoutSpace[0] = offscreenSpace
extraLayoutSpace[1] = offscreenSpace
}
// copied from ViewPager2.LinearLayoutManagerImp
override fun requestChildRectangleOnScreen(
parent: RecyclerView,
child: View,
rect: Rect,
immediate: Boolean,
focusedChildVisible: Boolean
): Boolean {
return false // users should use setCurrentItem instead
}
// this need to show MainPage bounds on left/right side menu
override fun checkLayoutParams(lp: RecyclerView.LayoutParams?): Boolean {
if (lp != null && lp.viewAdapterPosition in smallViewPosition) {
lp.width = (width * viewSmallPercentage).toInt()
}
return super.checkLayoutParams(lp)
}
override fun canScrollHorizontally(): Boolean {
return super.canScrollHorizontally() && viewPager.isEnabled
}
}
我用 ViewPager2 替换了 ViewPager,但我有问题。 ViewPager 已修复 3 个页面。第二页比其他页大。当第1页或第3页可见时,第2页的一小部分也可见,当第2页可见时,其他页面不可见。为此,我使用了适配器方法
override fun getPageWidth(position: Int): Float {
return if (position != MAIN_PAGE) WIDTH_SMALL_PERCENT
else super.getPageWidth(position)
}
但是 ViewPager2 的适配器没有这个方法,我不知道怎么做。
现在没有黑客是不可能的。我创建功能请求 https://issuetracker.google.com/issues/150232913.
并且在预期功能我创建扩展方法来设置自定义布局管理器
package androidx.viewpager2.widget
import androidx.recyclerview.widget.RecyclerView
import java.lang.reflect.Field
fun ViewPager2.setLayoutManager(layoutManager: RecyclerView.LayoutManager) {
mRecyclerView.layoutManager = layoutManager
mRecyclerView.clearOnChildAttachStateChangeListeners() // to ability set exact view size
setValueToField("mLayoutManager", layoutManager)
mScrollEventAdapter.setValueToField("mLayoutManager", layoutManager) // to correct work ViewPager2.OnPageChangeCallback
}
private fun Any.setValueToField(field: String, value: Any) {
val f1: Field = this.javaClass.getDeclaredField(field)
f1.isAccessible = true
f1.set(this, value)
f1.isAccessible = false
}
并创建自定义 LayoutManager
class WidePageLayoutManager(
private val viewPager: ViewPager2,
private val viewSmallPercentage: Float,
private val smallViewPosition: IntArray
) : LinearLayoutManager(viewPager.context, HORIZONTAL, false) {
// copied from ViewPager2.LinearLayoutManagerImp
override fun calculateExtraLayoutSpace(state: RecyclerView.State, extraLayoutSpace: IntArray) {
val pageLimit: Int = viewPager.offscreenPageLimit
val offscreenSpace: Int = viewPager.pageSize * pageLimit
extraLayoutSpace[0] = offscreenSpace
extraLayoutSpace[1] = offscreenSpace
}
// copied from ViewPager2.LinearLayoutManagerImp
override fun requestChildRectangleOnScreen(
parent: RecyclerView,
child: View,
rect: Rect,
immediate: Boolean,
focusedChildVisible: Boolean
): Boolean {
return false // users should use setCurrentItem instead
}
// this need to show MainPage bounds on left/right side menu
override fun checkLayoutParams(lp: RecyclerView.LayoutParams?): Boolean {
if (lp != null && lp.viewAdapterPosition in smallViewPosition) {
lp.width = (width * viewSmallPercentage).toInt()
}
return super.checkLayoutParams(lp)
}
override fun canScrollHorizontally(): Boolean {
return super.canScrollHorizontally() && viewPager.isEnabled
}
}