Android kotlin 自定义View 旋转、移动、放缩 ImageView

0、效果图

              

1、功能

功能:
放缩:三指操作
旋转:两只操作
移动:单指操作

 2、实现代码

import android.content.Context
import android.graphics.Matrix
import android.graphics.PointF
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import kotlin.math.atan

class RotateZoomImageView(context: Context, attrs: AttributeSet?) :
    androidx.appcompat.widget.AppCompatImageView(context, attrs) {

    private val TAG = "RotateZoomImageView"
    private var mScaleGestureDetector: ScaleGestureDetector

    private var mImageMatrix: Matrix = Matrix()
    private val savedMatrix: Matrix = Matrix()

    private var x = 0
    private var y = 0

    private var mLastAngle = 0

    // 第一个按下的手指的点
    private val startPoint = PointF()


    private val mScaleListener = object : ScaleGestureDetector.SimpleOnScaleGestureListener() {
        override fun onScale(detector: ScaleGestureDetector): Boolean {
            //缩放比例因子
            val scaleFactor = detector.scaleFactor
            mImageMatrix.postScale(scaleFactor, scaleFactor, x.toFloat(), y.toFloat())
            imageMatrix = mImageMatrix

            return true
        }
    }

    init {
        mScaleGestureDetector = ScaleGestureDetector(context, mScaleListener)
        scaleType = ScaleType.MATRIX
    }


    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        if (w != oldw || h != oldh) {
            val transX = (w - drawable.intrinsicWidth) / 2.0
            val transY = (h - drawable.intrinsicHeight) / 2.0
            mImageMatrix.setTranslate(transX.toFloat(), transY.toFloat())
            imageMatrix = mImageMatrix
            x = w / 2
            y = h / 2
        }
    }


    private fun doRotationEvent(ev: MotionEvent): Boolean {
        //计算两个手指的角度
        val dx = ev.getX(0) - ev.getX(1)
        val dy = ev.getY(0) - ev.getY(1)
        //弧度
        val radians = atan(dy.toDouble() / dx.toDouble())
        //角度
        val degrees = (radians * 180 / Math.PI).toInt()

        when (ev.actionMasked) {
            MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN, MotionEvent.ACTION_POINTER_UP -> mLastAngle =
                degrees
            MotionEvent.ACTION_MOVE -> {
                when {
                    (degrees - mLastAngle) > 45 -> mImageMatrix.postRotate(
                        -5f,
                        x.toFloat(),
                        y.toFloat()
                    )
                    (degrees - mLastAngle) < -45 -> mImageMatrix.postRotate(
                        5f,
                        x.toFloat(),
                        y.toFloat()
                    )
                    else -> mImageMatrix.postRotate(
                        (degrees - mLastAngle).toFloat(),
                        x.toFloat(),
                        y.toFloat()
                    )
                }
                imageMatrix = mImageMatrix
                mLastAngle = degrees
            }
        }

        return true
    }

    private fun doMoveEvent(ev: MotionEvent): Boolean {
        when (ev.actionMasked) {
            MotionEvent.ACTION_MOVE -> {
                mImageMatrix.set(savedMatrix)
                mImageMatrix.postTranslate(ev.x - startPoint.x, ev.y - startPoint.y)
                imageMatrix = mImageMatrix
            }
        }
        return true
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        if (event.action == MotionEvent.ACTION_DOWN) {
            Log.d("drag", "onTouch: x= ${event.rawX.toInt()},y=${event.rawY.toInt()}" )
            mImageMatrix.set(imageMatrix)
            savedMatrix.set(mImageMatrix)
            startPoint[event.x] = event.y
            return true
        }
        return when (event.pointerCount) {
            3 -> mScaleGestureDetector.onTouchEvent(event)
            2 -> doRotationEvent(event)
            1 -> doMoveEvent(event)
            else -> super.onTouchEvent(event)
        }
    }
}

3、布局引用

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".RotateImageActivity">


    <com.afei.cropphoto.RotateZoomImageView
        android:id="@+id/rotate_img"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginHorizontal="30dp"
        android:layout_marginVertical="50dp"
        android:background="#DEDDDD"
        android:src="@drawable/mv"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

猜你喜欢

转载自blog.csdn.net/QJQJLOVE/article/details/113736872