【问题标题】:Android: Create a swipe gesture event programmaticallyAndroid:以编程方式创建滑动手势事件
【发布时间】:2015-05-31 22:00:17
【问题描述】:

我一直试图在 Google 上找到这个特定案例的答案,但令人惊讶的是在任何地方都找不到它(只有关于检测而不是创建滑动的答案)。我想在屏幕上实际“运行”一个从右到左的模拟滑动(不管在哪里,但最好是从右边缘到左)。我尝试过这样的事情,但我得到了一个 NPE:

final float viewWidth = view.getWidth();
    TouchUtils.drag(null,viewWidth,1f,0f,0f,1);

原因?我需要在没有真正参考页面位置的无限视图页面中强制滑动到下一页(所以我不能只使用 setCurrentItem)。

有什么想法吗?

【问题讨论】:

  • "所以我不能只使用 setCurrentItem" -- 嗯,为什么不打电话给pager.setCurrentItem(pager.getCurrentItem()+1, true);?你可能认为它是“无限的”,但ViewPager 仍然使用项目位置。
  • 由于某种原因,这样做会导致整个应用程序冻结 - 而 logcat 没有帮助......
  • 好吧,TouchUtils 用于测试,而不是用于生产代码。虽然至少理论上可以为您自己的应用程序模拟触摸事件,但我不相信它会被证明是解决您的问题的稳定可靠的解决方案。我建议您设置一些断点并找出setCurrentItem() 不适合您的位置。
  • 我想使用测试类如仪器、Touchutils ..etc 进行生产.. 目的是从远程模拟我们的应用程序.. 是否可以在生产中使用测试类...?

标签: android android-viewpager gesture


【解决方案1】:

如前所述,TouchUtils.drag 使用 Instrumentation,只能在 androidTest 中使用。 我编写了不需要Instrumentation 的扩展函数,因此它们可以在发布构建中使用:

fun ViewGroup.performSwipeToLeft(target: View) {
    this.performSwipe(target, distanceX = -this.width * .5f, distanceY = 0f)
}
fun ViewGroup.performSwipeToRight(target: View) {
    this.performSwipe(target, distanceX = +this.width * .5f, distanceY = 0f)
}
fun ViewGroup.performSwipeToTop(target: View) {
    this.performSwipe(target, distanceX = 0f, distanceY = -this.height * .5f)
}
fun ViewGroup.performSwipeToBottom(target: View) {
    this.performSwipe(target, distanceX = 0f, distanceY = +this.width * .5f)
}

fun ViewGroup.performSwipe(target: View, distanceX: Float, distanceY: Float) {
    val parentCoords = intArrayOf(0, 0)
    this.getLocationInWindow(parentCoords)

    val childCoords = intArrayOf(0, 0)
    target.getLocationInWindow(childCoords)

    val initGlobalX = childCoords[0].toFloat() + 1f
    val initGlobalY = childCoords[1].toFloat() + 1f

    val initLocalX = (childCoords[0] - parentCoords[0]).toFloat() + 1f
    val initLocalY = (childCoords[1] - parentCoords[1]).toFloat() + 1f

    val downTime = SystemClock.uptimeMillis()
    var eventTime = SystemClock.uptimeMillis()

    this.dispatchTouchEvent(
        MotionEvent.obtain(
            downTime,
            eventTime,
            MotionEvent.ACTION_DOWN,
            initGlobalX,
            initGlobalY,
            0
        ).apply {
            setLocation(initLocalX, initLocalY)
            source = InputDevice.SOURCE_TOUCHSCREEN
        }
    )

    val steps = 20
    var i = 0
    while (i in 0..steps) {
        val globalX = initGlobalX + i * distanceX / steps
        val globalY = initGlobalY + i * distanceY / steps
        val localX = initLocalX + i * distanceX / steps
        val localY = initLocalY + i * distanceY / steps
        if (globalX <= 10f || globalY <= 10f) {
            break
        }
        this.dispatchTouchEvent(
            MotionEvent.obtain(
                downTime,
                ++eventTime,
                MotionEvent.ACTION_MOVE,
                globalX,
                globalY,
                0
            ).apply {
                setLocation(localX, localY)
                source = InputDevice.SOURCE_TOUCHSCREEN
            }
        )
        i++
    }

    this.dispatchTouchEvent(
        MotionEvent.obtain(
            downTime,
            ++eventTime,
            MotionEvent.ACTION_UP,
            initGlobalX + i * distanceX,
            initGlobalY + i * distanceY,
            0
        ).apply {
            setLocation(initLocalX + i * distanceX, initLocalY + i * distanceY)
            source = InputDevice.SOURCE_TOUCHSCREEN
        }
    )
}

要使用它,您需要将当前页面内容作为参数传递,并将 viewPager 作为此函数的接收者:

val viewPager = ...
viewPager.performSwipeToLeft(viewPager.getChildAt(viewPager.currentItem))

【讨论】:

    猜你喜欢
    • 2016-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-23
    • 1970-01-01
    • 2011-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多