自定义View之双指缩放图片的实现

前提

这篇文章是基于上篇文章 图片缩放的解决办法,另外实现的功能——双指缩放图片,上篇的代码只实现了通过触控点缩放图片的功能,然后在组长的帮助下我又自己尝实现了双指缩放图片的功能,当然还是基于上篇的代码完成的。

OK,进入正题

一、定义需要的变量

因为在实现这个功能时需要用到前一次的双指触摸点坐标和现在的双指触摸点的坐标来计算两次触摸点的距离比值从而获得缩放图片的缩放因子,用来确定图片需要缩小放大的倍数。

PS:缩放因子就是两手指间的初始距离当前距离的比值。

    // 上次双指触摸的 x1 的 x 坐标
    private var mLastDoubleTouchX1 = 0f

    // 上次双指触摸的 x1 的 y 坐标
    private var mLastDoubleTouchY1 = 0f

    // 上次双指触摸的 x2 的 x 坐标
    private var mLastDoubleTouchX2 = 0f

    // 上次双指触摸的 x2 的 7 坐标
    private var mLastDoubleTouchY2 = 0f


二、第一次记录双指触屏的坐标

然后需要在 ACTION_POINTER_DOWN 事件中记录首次双指在屏幕上长按的坐标,在安卓中 ACTION_POINTER_DOWN MotionEvent 的一个动作类型,在有新的手指触摸屏幕时触发,通常用于处理多点触控的场景,这个事件让你知道除了第一个触摸点外,又有一个或多个触摸点被添加到了当前的触摸操作中。

//当用户将第二个或更多的手指放到触摸屏上时,会触发 ACTION_POINTER_DOWN 事件
            ACTION_POINTER_DOWN -> {
                mLongClickJob?.cancel()
                mDegree = callRotation(event)
                // 更新最后触摸点的坐标
                mLastDoubleTouchX1 = event.getX(0)
                mLastDoubleTouchY1 = event.getY(0)
                mLastDoubleTouchX2 = event.getX(1)
                mLastDoubleTouchY2 = event.getY(1)
                mIsPointerDown = true
                return true
            }


三、处理移动事件

在记录下第一次双指与屏幕接触的两个坐标后,手指需要在屏幕上滑动,然后通过改变双指间距实现对图片的缩放,所以要在 ACTION_MOVE 事件中实现处理逻辑。在安卓中 ACTION_MOVE 用于指示手指正在屏幕上移动。

1、获取前一次和当前的双指间距

ACTION_MOVE 事件中调用 getDistanceOf2Points 方法计算两点之间的间距

    val LastPointsOfDistance = getDistanceOf2Points(
                        mLastDoubleTouchX1,
                        mLastDoubleTouchY1,
                        mLastDoubleTouchX2,
                        mLastDoubleTouchY2
                    )
    val nowPointsOfDistance = getDistanceOf2Points(event)

这里我在 MatrixlmageUtils.kt 文件中重载了 getDistanceOf2Points 的方法:

    internal fun getDistanceOf2Points(event: MotionEvent): Float {
        //第一个点的坐标
        val x1:Float = event.getX(0)
        val y1:Float = event.getY(0)
        //第二个点的坐标
        val x2:Float = event.getX(1)
        val y2:Float = event.getY(1)

        return sqrt((x1 - x2).pow(2) + (y1 - y2).pow(2))
    }

2、计算缩放因子

前面的已经获得了两手指间的初始距离当前距离,现在就可以解锁缩放因子,获得缩放图片的必要数据

     val scaleFactor = (nowPointsOfDistance / LastPointsOfDistance)

3、应用缩放因子

将得到的缩放因子应用到Matrix类实例化的mImgMatrix对象中

postScale (float sx, float sy, float px, float py) 方法接收四个参数:前面两个参数分别是X轴和Y轴方向的缩放比例,后面参数两个是缩放中心的X,Y坐标点。

PS:因为是等比缩放,所以X轴和Y轴方向的比例是一致的

  mImgMatrix.postScale(scaleFactor, scaleFactor, centerX, centerY)
  imageMatrix = scaleMatrix

4、更新最后触摸点的坐标

ACTION_MOVE 方法的最后,需要重新获取最后的触摸点坐标,这样才能不断计算正常的的缩放因子,否则前一次的双指坐标一直不被更新(因为第一的双指坐标是在ACTION_POINTER_DOWN 中所记录的),就会导致缩放因子比例过大,缩放不均匀的现象产生

       // 更新最后触摸点的坐标
       mLastDoubleTouchX1 = event.getX(0)
       mLastDoubleTouchY1 = event.getY(0)
       mLastDoubleTouchX2 = event.getX(1)
       mLastDoubleTouchY2 = event.getY(1)
       return true

 5、控制极端缩放大小

如果担心图片被缩的太小或者放的太大,可以用上次用的方法来设置图片尺寸最大和最小值:

        val scaleMatrix = Matrix(mImgMatrix)
        scaleMatrix.postScale(scaleFactor, scaleFactor, centerX, centerY)
        val scaleRectF = getImageRectF(this, scaleMatrix)
        if (scaleRectF.right - scaleRectF.left < mScaleDotRadius * 6 || scaleRectF.bottom - scaleRectF.top < mScaleDotRadius * 6) {
                return true
        }
        if (scaleRectF.right - scaleRectF.left > mScaleDotRadius * 300 || scaleRectF.bottom - scaleRectF.top > mScaleDotRadius * 300) {
                 return true
         }

        mImgMatrix.postScale(scaleFactor, scaleFactor, centerX, centerY)
        imageMatrix = scaleMatrix

 PS:看到网上也有用控制累计缩放因子大小的方法来限制尺寸的最大最小值,我也试了一下感觉效果不是很好,会有卡顿的感觉,可能是我没有处理好


三、源码

package tech.yangle.matriximage

import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Bitmap.createScaledBitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.PointF
import android.graphics.RectF
import android.util.AttributeSet
import android.util.Log
import android.util.TypedValue
import android.util.TypedValue.COMPLEX_UNIT_DIP
import android.view.MotionEvent
import android.view.MotionEvent.ACTION_CANCEL
import android.view.MotionEvent.ACTION_DOWN
import android.view.MotionEvent.ACTION_MASK
import android.view.MotionEvent.ACTION_MOVE
import android.view.MotionEvent.ACTION_POINTER_DOWN
import android.view.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值