Android:自定义View实现图片缩放及坐标的计算(下)

大家好,我是时曾相识2022。不喜欢唱跳篮球,但对杰伦的Rap却情有独钟。

书接上文Android:自定义View实现图片缩放及坐标的计算(上),咱们实现了图片的缩放。接下来我们继续说说描点和图片同步缩放的功能。

1.gif

刚开始我天真的以为缩放后的坐标点不就是当前坐标的乘以缩放比例:

firstPoint.apply {
    this.x = this.x * scale
    this.y = this.y * scale
}

结果运行后一缩放我们点不知道跑到哪里去了。因为从来没接触过这类需求,所以对这块功能比较陌生。于是各种网上搜索,最后总算是找到了希望。图片是通过矩阵进行缩放的,那么我们的点需要保持和图片缩放同步就一定的按照这个规则进行缩放才行。Matrix是一个3 x 3的矩阵,包含对平移、旋转、缩放、错切变换的处理。咱们用到的是缩放,可通过下面的方式获取到缩放后的坐标的:

val matrixValues = FloatArray(9)
mScaleMatrix.getValues(matrixValues)
val mscale_x = matrixValues[Matrix.MSCALE_X]
val mtrans_x = matrixValues[Matrix.MTRANS_X]
val mscale_y = matrixValues[Matrix.MSCALE_Y]
val mtrans_y = matrixValues[Matrix.MTRANS_Y]
firstPoint.apply {
    this.x = this.x * mscale_x + 1 * mtrans_x
    this.y = this.y * mscale_y + 1 * mtrans_y
}
lastPoint.apply {
    this.x = this.x * mscale_x + 1 * mtrans_x
    this.y = this.y * mscale_y + 1 * mtrans_y
}

找到方法的我暗自庆幸,怀着激动的心情运行后,看到效果的我甚至开始怀疑这个代码的可靠性。效果是随着放大的操作描的点逐渐消失在屏幕中。无论怎么修改调试始终不得其解。最后甚至给上面反应说实现起来太复杂了,可能做不了。虽然上面允许了可以不缩放的实现,但这件事一直在我脑海中浮现,其实后来想想觉得自己挺傻的。

转机:

当天我掐准了下班时间早早的上了车,脑海又回想起坐标计算的事情,突然灵光乍现我怎么会用当前坐标点去反复乘以缩放率呢?这样不就使其点越来越大,远远大于实际缩放的值了!问题一定是出现在这里。

firstPoint.apply {
    this.x = this.x * mscale_x + 1 * mtrans_x //this.x.x 这一步有问题
    this.y = this.y * mscale_y + 1 * mtrans_y //this.y.y 这一步有问题
}

第二天我一早到公司,自信的打开代码将左右坐标点给保存了一份。将原有代码修改为:

//firstPoint1 为备份的初始点坐标
firstPoint.apply {
   this.x = firstPoint1.x * mscale_x + 1 * mtrans_x
   this.y = firstPoint1.y * mscale_y + 1 * mtrans_y
}

再次怀着激动的心情运行代码,它成功了!!!

当前情景是默认不缩放的情况描点再进行缩放,一切正常。当默认情景时缩放后再进行描边呢?不用想确实有问题,就和刚开始的情况一样,没有实际的坐标点为基准,计算出来的坐标点就一定是不准的。

其实很好解决,我们可以根据当前缩放率通过反向计算,算出实际的坐标点。

this.x = this.x * mscale_x + 1 * mtrans_x
实际坐标点=(当前点-1 * mtrans_x)/mscale_x + 1

至此只要能获取原始的坐标点,缩放时根据原有坐标的根据缩放率计算出当前的坐标点,运行起来的效果基本没啥问题了。

总结:

  • 自定义View时选用最接近的View进行继承
  • 描两个点需要记录当前点数量,拖拽时需要判断触碰点的范围是否在mark范围内
  • 手势操作可使用ScaleGestureDetectorGestureDetector进行监管,很大程度上减少了逻辑判断。如果复杂场景无法实现还是需要在onTouch中进行逻辑判断
  • 点随图片缩放一定要注意转换时要使用原始的坐标点进行计算,不要使用当前点坐标去计算

以上便是自定义View实现图片缩放及坐标的计算的全部内容,希望对大家有所帮助!