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

如何使用InputManager模拟缩放(放大/缩小)手势?

Kotlin 用InputManager实现双指缩放手势模拟

要实现双指缩放(捏合/放大)手势,关键在于正确处理多指针触摸事件——使用ACTION_POINTER_DOWN添加第二个手指,通过MotionEvent的多指针API设置每个手指的坐标,最后用ACTION_POINTER_UP和ACTION_UP结束手势。以下是完整实现代码:

import android.hardware.input.InputManager
import android.view.InputEvent
import android.view.MotionEvent
import java.lang.reflect.Method
import android.os.SystemClock
import kotlin.concurrent.sleep

fun simulatePinchZoom(
    centerX: Int, centerY: Int, // 缩放中心点
    startDistance: Float,       // 初始双指距离
    endDistance: Float,         // 结束双指距离(大于startDistance是放大,反之缩小)
    duration: Long
) {
    try {
        // 反射获取InputManager实例
        val inputManagerClass = Class.forName("android.hardware.input.InputManager")
        val getInstanceMethod: Method = inputManagerClass.getMethod("getInstance")
        val inputManager = getInstanceMethod.invoke(null)

        val injectInputEventMethod: Method = inputManagerClass.getMethod(
            "injectInputEvent", InputEvent::class.java, Int::class.javaPrimitiveType
        )

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

        // 计算两个手指的初始位置(围绕中心点)
        val halfStartDist = startDistance / 2
        val finger1StartX = centerX - halfStartDist
        val finger1StartY = centerY.toFloat()
        val finger2StartX = centerX + halfStartDist
        val finger2StartY = centerY.toFloat()

        // 第一步:第一个手指按下(ACTION_DOWN)
        val downEvent1 = MotionEvent.obtain(
            downTime, eventTime, MotionEvent.ACTION_DOWN,
            floatArrayOf(finger1StartX, finger2StartX),
            floatArrayOf(finger1StartY, finger2StartY),
            0
        )
        injectInputEventMethod.invoke(inputManager, downEvent1, 0)
        sleep(50) // 短暂间隔模拟真实触摸

        // 第二步:第二个手指按下(ACTION_POINTER_DOWN,指针ID为1)
        eventTime += 50
        val downEvent2 = MotionEvent.obtain(
            downTime, eventTime, MotionEvent.ACTION_POINTER_DOWN or (1 shl MotionEvent.ACTION_POINTER_INDEX_SHIFT),
            floatArrayOf(finger1StartX, finger2StartX),
            floatArrayOf(finger1StartY, finger2StartY),
            0
        )
        injectInputEventMethod.invoke(inputManager, downEvent2, 0)
        sleep(50)

        // 第三步:双指移动实现缩放
        val steps = 100
        val stepDuration = duration / steps
        val distanceDelta = endDistance - startDistance
        val stepDelta = distanceDelta / steps

        var currentFinger1X = finger1StartX
        var currentFinger2X = finger2StartX

        for (i in 1..steps) {
            eventTime += stepDuration
            val currentHalfDist = halfStartDist + (stepDelta * i) / 2
            // 计算当前两个手指的坐标
            currentFinger1X = centerX - currentHalfDist
            currentFinger2X = centerX + currentHalfDist

            val moveEvent = MotionEvent.obtain(
                downTime, eventTime, MotionEvent.ACTION_MOVE,
                floatArrayOf(currentFinger1X, currentFinger2X),
                floatArrayOf(finger1StartY, finger2StartY),
                0
            )
            injectInputEventMethod.invoke(inputManager, moveEvent, 0)
            moveEvent.recycle()
            sleep(stepDuration)
        }

        // 第四步:抬起第二个手指(ACTION_POINTER_UP,指针ID为1)
        eventTime += 50
        val upEvent2 = MotionEvent.obtain(
            downTime, eventTime, MotionEvent.ACTION_POINTER_UP or (1 shl MotionEvent.ACTION_POINTER_INDEX_SHIFT),
            floatArrayOf(currentFinger1X, currentFinger2X),
            floatArrayOf(finger1StartY, finger2StartY),
            0
        )
        injectInputEventMethod.invoke(inputManager, upEvent2, 0)
        sleep(50)

        // 第五步:抬起第一个手指(ACTION_UP)
        eventTime += 50
        val upEvent1 = MotionEvent.obtain(
            downTime, eventTime, MotionEvent.ACTION_UP,
            floatArrayOf(currentFinger1X, currentFinger2X),
            floatArrayOf(finger1StartY, finger2StartY),
            0
        )
        injectInputEventMethod.invoke(inputManager, upEvent1, 0)

        // 回收事件资源
        downEvent1.recycle()
        downEvent2.recycle()
        upEvent2.recycle()
        upEvent1.recycle()
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

关键说明

  • 多指针事件处理:第二个手指按下用ACTION_POINTER_DOWN,抬起用ACTION_POINTER_UP,通过(指针ID shl MotionEvent.ACTION_POINTER_INDEX_SHIFT)指定操作的指针。
  • 坐标设置:使用MotionEvent.obtain的多参数版本,传入两个手指的X/Y坐标数组。
  • 缩放逻辑:通过调整两个手指相对于中心点的距离,模拟放大(距离增大)或缩小(距离减小)。
  • 时间同步:所有事件共用同一个downTime,eventTime逐步递增,模拟真实触摸的时间间隔。

你可以通过调用simulatePinchZoom(500, 500, 100f, 300f, 1000)来测试——以屏幕中心(500,500)为原点,初始双指距离100,放大到300,耗时1秒。

内容的提问来源于stack exchange,提问作者David

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 21:23:23