如何在ViewPager2页面切换时弹出确认告警 正确使用OnPageChangeCallback
问题分析
你现在的实现存在三个核心问题:
OnPageChangeCallback是页面滑动发生后的回调,无法在滑动动作触发前拦截切换行为,此时弹出弹窗时页面已经发生跳转,无法满足你拦截切换的需求onPageScrollStateChanged会在滑动状态变化(开始滑动、滑动中、滑动结束)时多次触发,会导致弹窗重复弹出- 你封装的
createAlert方法只创建了Dialog实例但没有调用show()方法,弹窗本身不会显示
正确实现方案
你需要先禁用ViewPager2的默认滑动能力,自行监听用户滑动手势,自定义切换逻辑:
步骤1:禁用默认滑动
// 关闭ViewPager2默认用户滑动能力,后续切换逻辑自己控制 binding?.ViewPager?.isUserInputEnabled = false
步骤2:监听滑动手势,触发确认弹窗
// 记录手指按下的坐标 private var downX = 0f private var downY = 0f // 系统识别最小滑动距离阈值 private val touchSlop by lazy { ViewConfiguration.get(requireContext()).scaledTouchSlop } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding?.ViewPager?.isUserInputEnabled = false // 给ViewPager2设置触摸监听,识别滑动意图 binding?.ViewPager?.setOnTouchListener { _, event -> when (event.action) { MotionEvent.ACTION_DOWN -> { downX = event.x downY = event.y false } MotionEvent.ACTION_MOVE -> { val offsetX = event.x - downX val offsetY = event.y - downY val currentItem = binding?.ViewPager?.currentItem ?: return@setOnTouchListener false val itemCount = binding?.ViewPager?.adapter?.itemCount ?: 0 // 判断是有效水平滑动 if (Math.abs(offsetX) > touchSlop && Math.abs(offsetX) > Math.abs(offsetY)) { val targetItem = if (offsetX > 0) currentItem - 1 else currentItem + 1 // 目标页合法且和当前页不同 if (targetItem in 0 until itemCount && targetItem != currentItem) { // 弹出确认框 createAlert(targetItem) return@setOnTouchListener true } } false } else -> false } } }
步骤3:修改弹窗逻辑,用户确认后手动切换页面
private fun createAlert(targetItem: Int) { AlertDialog.Builder(requireContext()) .setTitle("退出当前页?") .setMessage("如果离开当前页面,未保存的数据将会丢失,是否确认离开?") .setPositiveButton("确认") { _, _ -> // 用户确认后手动切换到目标页 binding?.ViewPager?.setCurrentItem(targetItem, true) } .setNegativeButton(android.R.string.cancel, null) .show() }
注意事项
- 如果你只需要在存在未保存数据的页面才拦截滑动,可以在触发弹窗前加判断条件,只有未保存数据时才弹框,否则直接调用
setCurrentItem切换页面即可 - 页面销毁时记得移除注册的回调避免内存泄漏:
override fun onDestroyView() { // 如果你之前注册了OnPageChangeCallback,在这里替换成你自己的回调实例移除 // binding?.ViewPager?.unregisterOnPageChangeCallback(yourCallback) super.onDestroyView() }
内容的提问来源于stack exchange,提问作者Abhishek Dutt
相关产品推荐
相关产品推荐

