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>