You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ViewPager2页面切换时弹出确认告警 正确使用OnPageChangeCallback

问题分析

你现在的实现存在三个核心问题:

  1. OnPageChangeCallback 是页面滑动发生后的回调,无法在滑动动作触发前拦截切换行为,此时弹出弹窗时页面已经发生跳转,无法满足你拦截切换的需求
  2. onPageScrollStateChanged 会在滑动状态变化(开始滑动、滑动中、滑动结束)时多次触发,会导致弹窗重复弹出
  3. 你封装的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 12:36:03