以编程方式在Android视图中触发滑动动作事件

时间:2019-04-02 23:30:34

标签: java android android-view

我正在尝试以编程方式触发视图中的滑动。还有其他问题的答案,但它们对我没有帮助。我还看到一些comments表示出于安全原因禁用了程序化拖动/滚动,是真的吗?我很乐意为此找到一个明确的答案。

我尝试了以下poster通过视频显示正常工作的方法,因此它应该正常工作! AndroidManifest中是否需要我的东西?我也尝试过scrollBy() API,但这不会滚动我的内容,而是将内容移到屏幕外。

此外,我已经在视图中注册了OnTouchListener,并看到以下代码复制了相同格式的事件触发(ACTION_DOWNACTION_MOVEACTION_UP)单击+拖动和鼠标滚轮都可以,尽管单击+拖动和鼠标滚轮可以工作,而编程式滚动/滑动不起作用。

        final Handler handler = new Handler();

        handler.post(new Runnable() {
            @Override
            public void run() {
                final MotionEvent event = MotionEvent.obtain(System.currentTimeMillis(), System.currentTimeMillis(), MotionEvent.ACTION_DOWN, 500, 700, 0);
                dispatchTouchEvent(event);
                event.recycle();
            }
        });

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                final MotionEvent event = MotionEvent.obtain(System.currentTimeMillis(), System.currentTimeMillis(), MotionEvent.ACTION_MOVE, 500, 700 ,0);
                dispatchTouchEvent(event);
                event.recycle();
            }
        }, 50);

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                final MotionEvent event = MotionEvent.obtain(System.currentTimeMillis(), System.currentTimeMillis(), MotionEvent.ACTION_MOVE, 500 ,700 + 400, 0);
                dispatchTouchEvent(event);
                event.recycle();
            }
        }, 100);

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                final MotionEvent event = MotionEvent.obtain(System.currentTimeMillis(), System.currentTimeMillis(), MotionEvent.ACTION_UP, 500, 700 + 400, 0);
                dispatchTouchEvent(event);
                event.recycle();
            }
        }, 1000);

2 个答案:

答案 0 :(得分:0)

使用androidx.test.uiautomator完全有可能-这是现实情况。我已经编写了此方法来测试无尽的滚动RecyclerView……只是因为我懒得滑动:

protected void fling(UiObject2 view, int speed, int pause) {
    Assert.assertThat(view, not(equalTo(null)));
    try {
        view.fling(Direction.DOWN, speed);
    } catch (StaleObjectException e) {
        Assert.fail();
    }
    sleep(pause);
}

使用adb shell input swipe进行事件自动化也是可以的...

在两种情况下,事件都不是来自经过测试的应用。

(在两种情况下)都依赖于android.permission.INJECT_EVENTS

在有根设备上,甚至不需要adb-请参见answer

答案 1 :(得分:0)

这是我的逃跑方法

 /**
 * Simulate touching a specific location and dragging to a new location.
 *
 * @param fromX X coordinate of the initial touch, in screen coordinates
 * @param toX Xcoordinate of the drag destination, in screen coordinates
 * @param fromY X coordinate of the initial touch, in screen coordinates
 * @param toY Y coordinate of the drag destination, in screen coordinates
 * @param stepCount How many move steps to include in the drag
 */
 fun fling(
        fromX: Float, toX: Float, fromY: Float,
        toY: Float, stepCount: Int
    ) {

        val inst = Instrumentation()

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

        var y = fromY
        var x = fromX

        val yStep = (toY - fromY) / stepCount
        val xStep = (toX - fromX) / stepCount

        var event = MotionEvent.obtain(
            downTime, eventTime,
            MotionEvent.ACTION_DOWN, fromX, fromY, 0
        )
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
            event.source = InputDevice.SOURCE_TOUCHSCREEN
        }
        inst.sendPointerSync(event)



        for (i in 0 until stepCount) {
            y += yStep
            x += xStep
            eventTime = SystemClock.uptimeMillis()
            event = MotionEvent.obtain(
                downTime, eventTime + stepCount,
                MotionEvent.ACTION_MOVE, x, y, 0
            )
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
                event.source = InputDevice.SOURCE_TOUCHSCREEN
            }
            inst.sendPointerSync(event)
        }

        eventTime = SystemClock.uptimeMillis() + stepCount.toLong() + 2
        event = MotionEvent.obtain(
            downTime, eventTime,
            MotionEvent.ACTION_UP, toX, toY, 0
        )

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
            event.source = InputDevice.SOURCE_TOUCHSCREEN
        }
        inst.sendPointerSync(event)
    }

这就是我的用法

 fab.setOnClickListener { view ->
            Thread(Runnable {
                try {

                    fling(500f ,900f ,530f ,20f, 5);
                   // emulateMptionEvent()

                } catch (e: Exception) {
                }
            }).start()
        }

这是它的工作方式:

之前

enter image description here

单击Fab按钮后,蓝色虚线将模拟飞行路径。

enter image description here