【问题标题】:Scroll Multiple ViewPagers at the same time with a gesture使用手势同时滚动多个 ViewPager
【发布时间】: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 并添加一个滚动侦听器,该侦听器将在其旁边滚动另一个寻呼机。
  • 这个想法是它应该支持在屏幕上的任何点上用手势滚动。到目前为止,我在包含ViewPagersConstraintLayout 上实现了滑动手势,但它还应该在滚动ViewPagers 之一时同时滚动所有ViewPagers,并且还应该支持在单击操作时滚动到下一页。

标签: android android-viewpager android-viewpager2


【解决方案1】:

下面的代码对我有用。虽然我不得不切换到ViewPager1

viewPager1.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
    viewPager2.scrollX = scrollX
}

viewPager2.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
    viewPager1.scrollX = scrollX
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多