Android Kotlin:缩放后保持附加ImageView在可缩放ImageView固定位置
Android中TouchImageView缩放时同步箭头ImageView位置与尺寸的解决方案
我用MikeOrtiz的TouchImageView实现了可缩放的ImageView,现在需要添加一个红色箭头ImageView指向山顶,要求主图缩放时箭头始终固定在山顶位置,且尺寸适配缩放比例。但目前缩放后箭头的位置和尺寸都无法跟随变化,试过多种方案要么无效要么不适合Kotlin,求解决办法。
当前XML布局代码:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <androidx.cardview.widget.CardView android:layout_width="match_parent" android:layout_height="230dp" android:layout_gravity="center"> <com.ortiz.touchview.TouchImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/black" android:src="@drawable/mountain"/> <ImageView android:id="@+id/arrowImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/arrow" /> </androidx.cardview.widget.CardView> </FrameLayout>
问题现象:
- 未缩放状态:箭头位置正确,指向山顶
- 已缩放状态:箭头位置偏移,无法匹配山顶位置,且尺寸未适配缩放比例
解决方案(Kotlin实现)
核心思路是监听TouchImageView的缩放/平移变换,通过图片矩阵将山顶的原始坐标转换为当前屏幕坐标,同时反向调整箭头尺寸,保证视觉上的一致性。
步骤1:修改布局
移除箭头的translationX/Y属性,添加唯一ID方便代码获取。
步骤2:Activity中实现同步逻辑
import android.graphics.Matrix import android.graphics.PointF import android.os.Bundle import android.widget.ImageView import androidx.appcompat.app.AppCompatActivity import com.ortiz.touchview.TouchImageView class MainActivity : AppCompatActivity() { // 山顶在原始图片中的相对坐标(需根据你的图片实际调整,范围0-1) private val peakRelativeX = 0.6f private val peakRelativeY = 0.2f // 箭头的原始尺寸(单位:dp) private val originalArrowWidth = 48f private val originalArrowHeight = 110f override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val touchImageView = findViewById<TouchImageView>(R.id.image) val arrowImageView = findViewById<ImageView>(R.id.arrowImageView) // 将dp转换为像素 val density = resources.displayMetrics.density val arrowWidthPx = originalArrowWidth * density val arrowHeightPx = originalArrowHeight * density // 监听TouchImageView的变换事件 touchImageView.setOnTouchImageViewListener(object : TouchImageView.OnTouchImageViewListener { override fun onMove() { val drawable = touchImageView.drawable ?: return val imgWidth = drawable.intrinsicWidth.toFloat() val imgHeight = drawable.intrinsicHeight.toFloat() val matrix = touchImageView.imageMatrix // 计算山顶在原始图片中的绝对坐标 val peakOriginalX = imgWidth * peakRelativeX val peakOriginalY = imgHeight * peakRelativeY // 将原始坐标转换为当前屏幕上的坐标 val screenPoint = PointF() matrix.mapPoints(screenPoint.array(), floatArrayOf(peakOriginalX, peakOriginalY)) // 获取当前缩放比例 val matrixValues = FloatArray(9) matrix.getValues(matrixValues) val currentScale = (matrixValues[Matrix.MSCALE_X] + matrixValues[Matrix.MSCALE_Y]) / 2 // 调整箭头尺寸:反向缩放,保证视觉大小不变 val newArrowWidth = arrowWidthPx / currentScale val newArrowHeight = arrowHeightPx / currentScale // 设置箭头位置:让箭头中心对准山顶坐标 val arrowLeft = screenPoint.x - newArrowWidth / 2 val arrowTop = screenPoint.y - newArrowHeight / 2 // 更新箭头布局参数 val layoutParams = arrowImageView.layoutParams.apply { width = newArrowWidth.toInt() height = newArrowHeight.toInt() } arrowImageView.layoutParams = layoutParams // 更新箭头位置 arrowImageView.x = arrowLeft arrowImageView.y = arrowTop } }) // 初始化箭头位置(布局完成后执行) touchImageView.post { val drawable = touchImageView.drawable ?: return@post val imgWidth = drawable.intrinsicWidth.toFloat() val imgHeight = drawable.intrinsicHeight.toFloat() val peakOriginalX = imgWidth * peakRelativeX val peakOriginalY = imgHeight * peakRelativeY // 初始状态无缩放,直接计算位置 val arrowLeft = peakOriginalX - arrowWidthPx / 2 val arrowTop = peakOriginalY - arrowHeightPx / 2 arrowImageView.x = arrowLeft arrowImageView.y = arrowTop arrowImageView.layoutParams.apply { width = arrowWidthPx.toInt() height = arrowHeightPx.toInt() } } } }
关键说明
- 相对坐标:用
peakRelativeX/Y(0-1范围)表示山顶在原始图片中的位置,避免因图片尺寸差异导致的适配问题。 - 矩阵转换:通过TouchImageView的
imageMatrix将原始图片坐标转换为当前屏幕坐标,确保箭头始终跟随山顶。 - 反向缩放:箭头尺寸随图片缩放比例反向调整,保证缩放后箭头在视觉上的大小不变。
- 初始化处理:通过
post方法在布局完成后设置初始位置,避免因drawable未加载导致的空指针问题。
内容的提问来源于stack exchange,提问作者GamerBlind
相关产品推荐
相关产品推荐

