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

Android中如何基于Kotlin实现双指聚焦两指中点的ImageView缩放?

Kotlin实现ImageView双指以两指中心缩放的方案

要实现类似图库的双指缩放(以两指中心点为锚点),可以通过自定义ImageView结合ScaleGestureDetector实现,核心是利用矩阵(Matrix)控制图片的缩放和平移,确保缩放中心始终是两指的接触点。

核心实现代码

自定义ZoomableImageView类

import android.content.Context
import android.graphics.Matrix
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.widget.ImageView

class ZoomableImageView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ImageView(context, attrs, defStyleAttr) {

    private val scaleDetector = ScaleGestureDetector(context, ScaleListener())
    private val transformMatrix = Matrix()
    private var currentScale = 1f
    // 单指拖动相关变量
    private var lastTouchX = 0f
    private var lastTouchY = 0f
    private var isDragging = false

    init {
        // 必须设置为MATRIX模式,才能手动控制图片变换
        scaleType = ScaleType.MATRIX
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                lastTouchX = event.x
                lastTouchY = event.y
                isDragging = true
            }
            MotionEvent.ACTION_MOVE -> {
                // 仅在未进行缩放时处理拖动
                if (isDragging && !scaleDetector.isInProgress) {
                    val dx = event.x - lastTouchX
                    val dy = event.y - lastTouchY
                    transformMatrix.postTranslate(dx, dy)
                    imageMatrix = transformMatrix
                    lastTouchX = event.x
                    lastTouchY = event.y
                }
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                isDragging = false
            }
        }
        // 优先处理缩放手势
        scaleDetector.onTouchEvent(event)
        return true
    }

    private inner class ScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener() {
        override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
            // 缩放开始时标记,避免和拖动冲突
            isDragging = false
            return true
        }

        override fun onScale(detector: ScaleGestureDetector): Boolean {
            val scaleFactor = detector.scaleFactor
            val newScale = currentScale * scaleFactor

            // 限制缩放范围(可根据需求调整最小/最大缩放比例)
            val clampedScale = newScale.coerceIn(1f, 4f)
            val actualScale = clampedScale / currentScale

            // 将View坐标系的触摸中心点转换为图片矩阵坐标系的点
            val touchPoints = floatArrayOf(detector.focusX, detector.focusY)
            transformMatrix.mapPoints(touchPoints)
            val imageFocusX = touchPoints[0]
            val imageFocusY = touchPoints[1]

            // 以图片内部的中心点为锚点进行缩放
            transformMatrix.postScale(actualScale, actualScale, imageFocusX, imageFocusY)

            imageMatrix = transformMatrix
            currentScale = clampedScale
            return true
        }
    }
}

关键细节说明

  • ScaleType.MATRIX:必须设置此缩放模式,才能通过Matrix手动控制图片的缩放、平移变换。
  • 坐标转换:通过matrix.mapPoints()将View上的触摸点转换为图片内部的坐标,确保缩放锚点是图片上的对应位置,而不是View的固定中心点。
  • 缩放范围限制:使用coerceIn()限制缩放比例,避免过度缩放导致图片失真或过小。
  • 手势冲突处理:通过isDragging和scaleDetector.isInProgress区分拖动和缩放手势,避免两种操作互相干扰。

使用方法

在布局文件中直接引用自定义View即可:

<com.yourpackage.ZoomableImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/your_target_image" />

可选优化

  • 添加边界检测:当图片缩放后小于View尺寸时自动居中;拖动时限制图片不能完全移出View可视区域。
  • 双击缩放:可以在onTouchEvent中添加双击事件的判断,实现双击放大/缩小的功能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 13:35:09