【发布时间】:2021-10-11 18:32:06
【问题描述】:
我想使用滑动手势同时水平滚动一组ViewPagers。用户应该能够在手势的每个点慢慢滚动到所需的位置(即ViewPagers 滚动应该与用户手势的 x 轴对齐。我几乎实现了我需要的,但是在我的实现中, ViewPagers 的滚动都没有完全“锁定/同步”,如果用户做出一个非常小的手势,ViewPager 之一快速磁性滚动到下一页,而另一个则停留在手指位置。我不'不知道这是否是由于ViewPager 上的页面的磁效应,但似乎是这样。我想知道是否有人知道如何解决这个问题。
我在这里上传了一个演示项目: https://github.com/JoseGbel/sync-scrolling-multiple-viewpager2
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val viewPager1 = findViewById<ViewPager2>(R.id.view_pager1)
val viewPager2 = findViewById<ViewPager2>(R.id.view_pager2)
val layout = findViewById<ConstraintLayout>(R.id.layout)
val stringsForVP1 = listOf(
"At vero eos et accusamus et iusto odio dignissimos",
"ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti"
)
val stringsForVP2 = listOf(
"ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti",
"At vero eos et accusamus et iusto odio dignissimos"
)
viewPager1.adapter = ViewPagerAdapter(this, stringsForVP1)
viewPager2.adapter = ViewPagerAdapter(this, stringsForVP2)
layout.setOnTouchListener(object : OnSwipeTouchListener(this@MainActivity.application as Context) {
override fun onSwipe(offset: Float?) {
offset?.let {
val offset = convertPixelsToDp(it, applicationContext)
viewPager1.beginFakeDrag()
viewPager1.fakeDragBy(offset)
viewPager1.endFakeDrag()
viewPager2.beginFakeDrag()
viewPager2.fakeDragBy(offset)
viewPager2.endFakeDrag()
}
super.onSwipe(offset)
}
})
}
}
class ViewPagerAdapter(
private val context: Context,
private val items: List<String>
) : RecyclerView.Adapter<ViewPagerAdapter.ViewHolder>() {
inner class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
fun bind(string: String) {
val textView = itemView.findViewById<TextView>(R.id.string_fragment_value_text_view)
textView.text = string
}
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): ViewHolder {
val itemView = LayoutInflater.from(context).inflate(R.layout.view_pager_element, parent, false)
return ViewHolder(itemView)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(items[position])
}
override fun getItemCount() = items.size
}
fun convertPixelsToDp(px: Float, context: Context): Float {
return px / (context.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
}
自定义 OnSwipeListener
open class OnSwipeTouchListener(ctx: Context) : View.OnTouchListener {
private val gestureDetector: GestureDetector
var difference : Float? = null
var startingXCoordinate : Float? = null
init {
gestureDetector = GestureDetector(ctx, GestureListener())
}
override fun onTouch(v: View, event: MotionEvent): Boolean {
if(event.action == MotionEvent.ACTION_DOWN){
startingXCoordinate = event.rawX
}
if(event.action == MotionEvent.ACTION_MOVE) {
difference = event.rawX - (startingXCoordinate ?: throw IllegalStateException("Starting coordinate was not defined"))
onSwipe(difference)
}
return gestureDetector.onTouchEvent(event)
}
private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
override fun onDown(e: MotionEvent): Boolean {
return true
}
}
open fun onSwipe(offset: Float?) {}
}
【问题讨论】:
-
是否必须仅来自触摸?
ViewPager2的优势在于它基于RecycleView,因此您可以快速破解viewPager1.getChildAt(0) as RecyclerView并添加一个滚动侦听器,该侦听器将在其旁边滚动另一个寻呼机。 -
这个想法是它应该支持在屏幕上的任何点上用手势滚动。到目前为止,我在包含
ViewPagers的ConstraintLayout上实现了滑动手势,但它还应该在滚动ViewPagers之一时同时滚动所有ViewPagers,并且还应该支持在单击操作时滚动到下一页。
标签: android android-viewpager android-viewpager2