"我正在参与「启航计划」" 这是我的第二篇文章

我发现大家对于实用性强的文章更感兴趣,这儿就写一下之前写的一个自定义一个支撑手势缩放以及点击旋转的控件

无图无本相,先上效果图

一、主要实现流程如下:

  1. 说到Android中的缩放,那肯定与scaleX,scaleY有关,经过这两个api能够方便的实现view的扩大缩小 可是这样的话会有问题咱们能够幻想一下假定手机是1080×1920,控件巨细也是1080×1920, 这时刚好填充满手机屏幕,可是当扩大一倍后
    就会出现问题,什么问题呢?假定原先控件上四个边角都有一个4×4的带色彩的小方块,当控件扩大两倍后为2160×3840,这时手机屏幕中内容显现不全 鉴于这种问题咱们一般是让该控件可被用户拖拽检查,拖拽的话就要使用到translationX,与translationY

  2. 既然是平移那就触及到了x与y方向能够平移多远间隔的问题,有一个平移鸿沟,这个鸿沟便是咱们缩放增加的巨细,
    假如说缩放到2160×3840,x方向增大了1080,那么能够向左向右各平移最多540的间隔,具体的移动能够在 onTouchEvent方法中进行核算设置,
    另外在进行缩放操作时假如发现控件的x,y进行过平移那么将translationX,与translationY置为0进行一个复位

  3. 到了这儿缩放与平移现已完结,后面便是经过手势双指进行一个缩放操作,经过 event的MotionEvent.ACTION_POINTER_DOWN,检测双指事情
    然后经过三角函数得到两点之间的间隔spacing1,缩放时分移动得到两指间隔spacing2,得到缩放系数 spacing = spacing2/spacing1 然后乘以现有的缩放份额:mScaleFactor = mScaleFactor * spacing,得到控件将要缩放的份额,在缩放过程中也要进行缩放鸿沟的判别

  4. 现在要害便是旋转问题了,由于旋转后控件宽高比较于屏幕宽高改变,一些缩放系数与鸿沟判别能够看doSetCWRotation方法,另外移动的时分也是要根据旋转视点进行判别的

二、代码如下:

细节当地代码中有相关注释

xml文件:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    tools:context=".MainActivity">
    <com.example.mytestdemo.scale.zoom.HomeworkZoomView
        android:id="@+id/scale_view"
        android:layout_width="match_parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:background="#E11F1F"
        android:visibility="visible"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:layout_width="100dp"
            android:background="@color/black"
            android:layout_height="100dp">
            <TextView
                android:layout_width="wrap_content"
                android:text="left"
                android:layout_gravity="center"
                android:textColor="@color/purple_700"
                android:textSize="16sp"
                android:layout_height="wrap_content"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_gravity="center"
            android:orientation="vertical"
            android:gravity="center"
            android:layout_height="wrap_content">
            <Button
                android:id="@+id/tv_rotation"
                android:layout_width="wrap_content"
                android:text="旋转"
                android:textColor="@color/purple_700"
                android:textSize="16sp"
                android:layout_height="wrap_content"/>
            <Button
                android:id="@+id/tv_add_scale"
                android:layout_width="wrap_content"
                android:text="扩大"
                android:textColor="@color/purple_700"
                android:textSize="16sp"
                android:layout_height="wrap_content"/>
            <Button
                android:id="@+id/tv_reduce_scale"
                android:layout_width="wrap_content"
                android:text="减小"
                android:textColor="@color/purple_700"
                android:textSize="16sp"
                android:layout_height="wrap_content"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="100dp"
            android:background="@color/black"
            android:layout_gravity="right"
            android:layout_height="100dp">
            <TextView
                android:layout_width="wrap_content"
                android:text="right"
                android:layout_gravity="center"
                android:textColor="@color/purple_700"
                android:textSize="16sp"
                android:layout_height="wrap_content"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="100dp"
            android:background="@color/black"
            android:layout_gravity="bottom|left"
            android:layout_height="100dp">
            <TextView
                android:layout_width="wrap_content"
                android:text="bottom|left"
                android:layout_gravity="center"
                android:textColor="@color/purple_700"
                android:textSize="16sp"
                android:layout_height="wrap_content"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="100dp"
            android:background="@color/black"
            android:layout_gravity="bottom|right"
            android:layout_height="100dp">
            <TextView
                android:layout_width="wrap_content"
                android:text="bottom right"
                android:layout_gravity="center"
                android:textColor="@color/purple_700"
                android:textSize="16sp"
                android:layout_height="wrap_content"/>
        </LinearLayout>
    </com.example.mytestdemo.scale.zoom.HomeworkZoomView>
</LinearLayout>

控件源码

package com.example.mytestdemo.scale.zoom
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.PropertyValuesHolder
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.MotionEvent
import android.view.animation.DecelerateInterpolator
import android.widget.FrameLayout
import androidx.core.view.GestureDetectorCompat
/**
 * @Description:支撑控件缩放,旋转, 双击扩大缩小,制作, 生成图片等
 * @Author: tgw
 * @CreateDate: 2022/4/22 10:46
 */
class HomeworkZoomView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
    var TAG = "HomeworkZoomView"
    // 属性变量
    private var translationX // 移动X
            = 0f
    private var translationY // 移动Y
            = 0f
    private var mScaleFactor = 1f // 伸缩份额
    private var mRotation // 旋转视点
            = 0
    // 移动过程中暂时变量
    private var actionX = 0f
    private var actionY = 0f
    private var spacing = 0f
    private var moveType // 0=未挑选,1=correct_tool_drag,2=缩放
            = 0
    //动画正在履行中
    private var isDoing = false
    private val MAX_SCALE = 2.0f
    private val MIN_SCALE = 1.0f
    var mGestureDetector: GestureDetectorCompat? = null
    private var mLastTouchX = 0f
    private var mLastTouchY = 0f
    private var originWidth //控件的原始长度
            = 0
    private var originHeight //控件的原始宽度
            = 0
    private var originScale = 1f //缩放的回弹参数,作为缩放份额最小系数
    private val isOpenMultiFingered = false
    private fun init(context: Context) {
        mGestureDetector = GestureDetectorCompat(getContext(), CorrectGestureListener())
    }
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        //获取控件的长宽
        originWidth = MeasureSpec.getSize(widthMeasureSpec)
        originHeight = MeasureSpec.getSize(heightMeasureSpec)
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    }
    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
        //getParent().requestDisallowInterceptTouchEvent(true);
//        if(ev.getAction() == MotionEvent.ACTION_MOVE){
//            if(mScaleFactor == 1){
//                return false;
//            }
//        }
        return super.onInterceptTouchEvent(ev)
    }
    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        return super.dispatchTouchEvent(ev)
    }
    interface OnSetTouchEventListener {
        fun setTouchEvent(event: MotionEvent?)
        fun cancel()
    }
    private var setTouchEventListener: OnSetTouchEventListener? = null
    fun setTouchEvent(setTouchEventListener: OnSetTouchEventListener?) {
        this.setTouchEventListener = setTouchEventListener
    }
    var notDo = false
    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        // Log.e("seesee", "onTouchEvent " + event.getActionMasked());
        if (isDoing) {
            return super.onTouchEvent(event)
        }
        if (isOpenMultiFingered) {
            if (event.pointerCount == 1) {
                if (setTouchEventListener != null) {
                    setTouchEventListener!!.setTouchEvent(event)
                    parent.requestDisallowInterceptTouchEvent(true)
                    return super.onTouchEvent(event)
                }
            }
            if (event.actionMasked == MotionEvent.ACTION_POINTER_DOWN) {
                if (setTouchEventListener != null) {
                    setTouchEventListener!!.cancel()
                }
            }
        }
        //注册双击事情
        if (mGestureDetector != null) {
            val a = mGestureDetector!!.onTouchEvent(event)
        }
        when (event.action and MotionEvent.ACTION_MASK) {
            MotionEvent.ACTION_DOWN -> {
                moveType = 1
                actionX = event.rawX
                actionY = event.rawY
            }
            MotionEvent.ACTION_POINTER_DOWN -> {
                moveType = 2
                spacing = getSpacing(event)
                mLastTouchX = event.rawX
                mLastTouchY = event.rawY
                Log.d(TAG, "onTouchEvent ACTION_POINTER_DOWN mLastTouchX: $mLastTouchX")
                Log.d(TAG, "onTouchEvent ACTION_POINTER_DOWN mLastTouchY: $mLastTouchY")
            }
            MotionEvent.ACTION_MOVE -> if (isOpenMultiFingered) {
                Log.d(TAG, "onTouchEvent isOpenMultiFingered mScaleFactor: $mScaleFactor")
                Log.d(TAG, "onTouchEvent isOpenMultiFingered spacing: $spacing")
                mScaleFactor = mScaleFactor * getSpacing(event) / spacing
                Log.d(TAG, "onTouchEvent isOpenMultiFingered mScaleFactor: $mScaleFactor")
                val canScale = checkScaleBound()
                if (canScale) {
                    //缩放过程中方位偏移
                    val disX = event.rawX - mLastTouchX
                    val disY = event.rawY - mLastTouchY
                    Log.d(TAG, "onTouchEvent isOpenMultiFingered translationX: $translationX")
                    Log.d(TAG, "onTouchEvent isOpenMultiFingered translationY: $translationY")
                    setTranslationXY(translationX + disX, translationY + disY)
                }
                mLastTouchX = event.rawX
                mLastTouchY = event.rawY
            } else {
                if (moveType == 1) {
                    var canMove = false
                    canMove = if (mRotation == 90 || mRotation == 270) {
                        checkRotationTranslation(event.rawX - actionX, event.rawY - actionY)
                    } else {
                        checkTranslation(event.rawX - actionX, event.rawY - actionY)
                    }
                    actionX = event.rawX
                    actionY = event.rawY
                    if (!canMove) {
                        zoomNotHandler = true
                        parent.requestDisallowInterceptTouchEvent(false)
                    } else {
                        zoomNotHandler = false
                    }
                } else if (moveType == 2) {
                    Log.d(TAG, "onTouchEvent moveType == 2 mScaleFactor: $mScaleFactor")
                    Log.d(TAG, "onTouchEvent moveType == 2 spacing: $spacing")
                    mScaleFactor = mScaleFactor * getSpacing(event) / spacing
                    Log.d(TAG, "onTouchEvent moveType == 2 mScaleFactor: $mScaleFactor")
                    val canScale = checkScaleBound()
                    if (canScale) {
                        //缩放过程中方位偏移
                        val disX = event.rawX - mLastTouchX
                        val disY = event.rawY - mLastTouchY
                        Log.d(TAG, "onTouchEvent moveType == 2 mLastTouchX: $mLastTouchX")
                        Log.d(TAG, "onTouchEvent moveType == 2 mLastTouchY: $mLastTouchY")
                        Log.d(TAG, "onTouchEvent moveType == 2 disX: $disX")
                        Log.d(TAG, "onTouchEvent moveType == 2 disY: $disY")
                        Log.d(TAG, "onTouchEvent moveType == 2 event.getRawX(): " + event.rawX)
                        Log.d(TAG, "onTouchEvent moveType == 2  event.getRawY(): " + event.rawY)
                        Log.d(TAG, "onTouchEvent moveType == 2  translationX: $translationX")
                        Log.d(TAG, "onTouchEvent moveType == 2  translationY: $translationY")
                        setTranslationXY(translationX + disX, translationY + disY)
                    }
                    mLastTouchX = event.rawX
                    mLastTouchY = event.rawY
                    Log.d(TAG, "onTouchEvent moveType == 2  endm LastTouchX: $mLastTouchX")
                    Log.d(TAG, "onTouchEvent moveType == 2  endm mLastTouchY: $mLastTouchY")
                }
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP -> {
                upAnimator(moveType)
                moveType = 0
            }
        }
        return super.onTouchEvent(event)
    }
    private fun checkTranslation(disX: Float, disY: Float): Boolean {
        //判别左右滑,仍是上下滑
        //假如制作区域在可视范围内,则不能滑动x,y坐标
        val width = originWidth
        val height = originHeight
        val tempWidth = width * mScaleFactor
        val tempHeight = height * mScaleFactor
        //        if(mRotation == 90 || mRotation == 270){
//            tempWidth = height*mScaleFactor;
//            tempHeight = width*mScaleFactor;
//        }
        Log.d(TAG, "checkTranslation width: $width")
        Log.d(TAG, "checkTranslation height: $height")
        Log.d(TAG, "checkTranslation mScaleFactor: $mScaleFactor")
        Log.d(TAG, "checkTranslation tempWidth: $tempWidth")
        Log.d(TAG, "checkTranslation tempHeight: $tempHeight")
        val canMove = true
        if (tempWidth <= width && tempHeight <= height) {
            return false
        }
        var resultX = translationX + disX
        var resultY = translationY + disY
        Log.d(TAG, "checkTranslation disX: $disX")
        Log.d(TAG, "checkTranslation disY: $disY")
        Log.d(TAG, "checkTranslation translationX: $translationX")
        Log.d(TAG, "checkTranslation translationY: $translationY")
        Log.d(TAG, "checkTranslation resultX: $resultX")
        Log.d(TAG, "checkTranslation resultY: $resultY")
        if (tempWidth <= width) {
            resultX = translationX //不动
        } else {
            val maxWDis = (tempWidth - width) / 2
            if (resultX <= -maxWDis) {
                resultX = -maxWDis
                //                canMove = false;
            } else if (resultX >= maxWDis) {
                resultX = maxWDis
                //                canMove = false;
            } else {
                parent.requestDisallowInterceptTouchEvent(true)
            }
        }
        if (tempHeight <= height) {
            resultY = translationY
        } else {
            val maxHDis = (tempHeight - height) / 2
            if (resultY <= -maxHDis) {
                resultY = -maxHDis
                //                canMove = false;
            } else if (resultY >= maxHDis) {
                resultY = maxHDis
                //                canMove = false;
            } else {
                parent.requestDisallowInterceptTouchEvent(true)
            }
        }
        if (canMove) {
            //doUp = false;
            setTranslationXY(resultX, resultY)
        }
        return canMove
    }
    private fun checkRotationTranslation(disX: Float, disY: Float): Boolean {
        //判别左右滑,仍是上下滑
        //假如制作区域在可视范围内,则不能滑动x,y坐标
        val width = originWidth
        val height = originHeight
        val tempWidth = height * mScaleFactor
        val tempHeight = width * mScaleFactor
        Log.d(TAG, "checkTranslation width: $width")
        Log.d(TAG, "checkTranslation height: $height")
        Log.d(TAG, "checkTranslation mScaleFactor: $mScaleFactor")
        Log.d(TAG, "checkTranslation tempWidth: $tempWidth")
        Log.d(TAG, "checkTranslation tempHeight: $tempHeight")
        var canMove = true
        if (tempWidth <= width && tempHeight <= height) {
            return false
        }
        var resultX = translationX + disX
        var resultY = translationY + disY
        Log.d(TAG, "checkTranslation disX: $disX")
        Log.d(TAG, "checkTranslation disY: $disY")
        Log.d(TAG, "checkTranslation translationX: $translationX")
        Log.d(TAG, "checkTranslation translationY: $translationY")
        Log.d(TAG, "checkTranslation resultX: $resultX")
        Log.d(TAG, "checkTranslation resultY: $resultY")
        if (tempWidth <= width) {
            resultX = translationX //不动
        } else {
            val maxWDis = (tempWidth - width) / 2
            if (resultX <= -maxWDis) {
                resultX = -maxWDis
                canMove = false
            } else if (resultX >= maxWDis) {
                resultX = maxWDis
                canMove = false
            } else {
                parent.requestDisallowInterceptTouchEvent(true)
            }
        }
        if (tempHeight <= height) {
            resultY = translationY
        } else {
            val maxHDis = (tempHeight - height) / 2
            if (resultY <= -maxHDis) {
                resultY = -maxHDis
                canMove = false
            } else if (resultY >= maxHDis) {
                resultY = maxHDis
                canMove = false
            } else {
                parent.requestDisallowInterceptTouchEvent(true)
            }
        }
        if (canMove) {
            //doUp = false;
            setTranslationXY(resultX, resultY)
        }
        return canMove
    }
    private fun upAnimator(moveType: Int) {
        if (isDoing || moveType != 2) return  //双击事情缩放中回来
        val width = originWidth
        val height = originHeight
        var tempWidth = width * mScaleFactor
        var tempHeight = height * mScaleFactor
        if (mRotation == 90 || mRotation == 270) {
            tempWidth = height * mScaleFactor
            tempHeight = width * mScaleFactor
        }
        //没有改变则不需求判别
        if (translationX == 0f && translationY == 0f && mScaleFactor == originScale) {
            return
        }
        val resultX: Float
        val resultY: Float
        if (mRotation == 90 || mRotation == 270) {
            resultX = (1 - mScaleFactor) * originHeight + Math.abs(translationX)
            resultY = (1 - mScaleFactor) * originWidth + Math.abs(translationY)
            Log.d(TAG, "upAnimator mScaleFactor: $mScaleFactor")
            Log.d(TAG, "upAnimator tempHeight: $tempHeight")
            Log.d(TAG, "upAnimator tempWidth: $tempWidth")
            Log.d(TAG, "upAnimator width: $width")
            Log.d(TAG, "upAnimator height: $height")
            Log.d(
                TAG,
                "upAnimator (1 - mScaleFactor) * originHeight: " + (1 - mScaleFactor) * originHeight
            )
            Log.d(
                TAG,
                "upAnimator (1 - mScaleFactor) * originWidth: " + (1 - mScaleFactor) * originWidth
            )
            Log.d(
                TAG,
                "upAnimator ((1 - mScaleFactor) * originHeight - width) / 2: " + ((1 - mScaleFactor) * originHeight - width) / 2
            )
            Log.d(
                TAG,
                "upAnimator ((1 - mScaleFactor) * originWidth - height) / 2: " + ((1 - mScaleFactor) * originWidth - height) / 2
            )
            Log.d(TAG, "upAnimator translationX: $translationX")
            Log.d(TAG, "upAnimator translationY: $translationY")
            Log.d(TAG, "upAnimator resultX: $resultX")
            Log.d(TAG, "upAnimator resultY: $resultY")
            val isNeedBack = isRotationNeedBack(
                mScaleFactor,
                resultX,
                resultY,
                originWidth.toFloat(),
                originHeight.toFloat()
            )
            //根据调查,向下滑translationY大于0,向上滑translationY小于0
            //在缩放系数小于1的时分,resultY永久大于0,当缩小时,缩小的间隔加上 移动间隔的绝对值小于当时的布局的一半时
            if (isNeedBack) {
                zoomAnimator(mScaleFactor, originScale, 0f, 0f)
                return
            }
        } else {
            resultX = (1 - mScaleFactor) * originWidth + Math.abs(translationX)
            resultY = (1 - mScaleFactor) * originHeight + Math.abs(translationY)
            val isNeedBack = isRotationNeedBack(
                mScaleFactor,
                resultX,
                resultY,
                originHeight.toFloat(),
                originWidth.toFloat()
            )
            if (isNeedBack) {
                zoomAnimator(mScaleFactor, originScale, 0f, 0f)
                return
            }
        }
    }
    private fun isNeedBack(
        resultX: Float,
        resultY: Float,
        tempWidth: Float,
        tempHeight: Float
    ): Boolean {
        if (resultX > 0) {
            return true
        } else if (resultX + tempWidth < originWidth) {
            return true
        }
        if (resultY > 0) {
            return true
        } else if (resultY + tempHeight < originHeight) {
            return true
        }
        return false
    }
     /**
     * 判别扩大的时分旋转,判别是否需求还原巨细
     */
    private fun isRotationNeedBack(
        scaleFactor: Float,
        resultX: Float,
        resultY: Float,
        originHeight: Float,
        originWidth: Float
    ): Boolean {
        //根据调查,向下滑translationY大于0,向上滑translationY小于0
        //在缩放系数小于1的时分,resultY永久大于0,当缩小时,缩小的间隔加上 移动间隔的绝对值,小于当时的布局的一半时,
        // 以为你应该要恢复原状了,避免缩小时 偏移到到看不见了
        //在缩放系数大于1的时分,((1 - mScaleFactor) * originWidth)的值,假定mScaleFactor为最大的2倍时,
        // 当未移动时resultY=-originWidth,当移动后就会translationX就会发生偏移量(上面获得绝对值:即偏移量)
        //当缩小时,((1 - mScaleFactor) * originWidth)的值会变小,当缩放的巨细+偏移量>0时
        // 以为整体应该要恢复原状了,避免缩小时 偏移到到看不见了
        var isNeedBack = false
        if (scaleFactor < 1 && resultY > originHeight / 2) { //当90时原始宽高颠倒
            isNeedBack = true
        } else if (scaleFactor > 1 && resultY > 0) {
            //在缩放系数>于1的时分,resultY永久大于0,当缩小时,
            // 缩小的间隔加上 移动间隔的绝对值小于当时的布局的一半时
            isNeedBack = true
        }
        if (scaleFactor < 1 && resultX > originWidth / 2) {
            isNeedBack = true
        } else if (scaleFactor > 1 && resultX > 0) {
            isNeedBack = true
        }
        return isNeedBack
    }
     /**
     * 移动拖拽view
     */
    private fun setTranslationXY(transX: Float, transY: Float) {
        translationX = transX
        translationY = transY
        Log.d(TAG, "setTranslationXY translationX: $translationX")
        Log.d(TAG, "setTranslationXY translationY: $translationY")
        //Log.e("xxyy", "translationX="+translationX+" || translationY="+translationY);
        setTranslationX(translationX)
        setTranslationY(translationY)
    }
    /**
     * 缩放鸿沟值判别
     *
     * @return 判别达到鸿沟值中止后续操作
     */
    private fun checkScaleBound(): Boolean {
        val canScale: Boolean
        Log.d(TAG, "checkScaleBound--mScaleFactor: $mScaleFactor")
        Log.d(TAG, "checkScaleBound--mScaleFactor--: " + mScaleFactor / originScale)
        if (getTranslationX() != 0f || getTranslationY() != 0f) {
            setTranslationXY(0f, 0f)
        }
        if (mScaleFactor < originScale) {
            canScale = false
            mScaleFactor = originScale
        } else if (mScaleFactor > 2 * originScale) {
            canScale = false
            mScaleFactor = 2 * originScale
        } else {
            canScale = true
            parent.requestDisallowInterceptTouchEvent(true)
        }
        scaleX = mScaleFactor
        scaleY = mScaleFactor
        return canScale
    }
     /**
     * 设置确认视点
     */
    fun doSetRotation(rotation: Int) {
        mRotation = rotation
        var tempScale = 1f
        setTranslationX(0.also { translationX = it.toFloat() }.toFloat())
        setTranslationY(0.also { translationY = it.toFloat() }.toFloat())
        if (mRotation == 0) {
            originScale = 1f
            tempScale = 1f
        } else if (mRotation == 90) {
            originScale = this.height.toFloat() / this.width
            tempScale = originScale
        } else if (mRotation == 180) {
            originScale = 1f
            tempScale = 1f
        } else if (mRotation == 270) {
            originScale = this.height.toFloat() / this.width
            tempScale = originScale
        }
        mScaleFactor = mScaleFactor * tempScale
        checkScaleBound()
        this.rotation = mRotation.toFloat()
    }
    /**
     * 对外方法,动态旋转,规则四个视点,顺时针
     */
    fun doSetCWRotation() {
        var tempScale = 1f
        setTranslationX(0.also { translationX = it.toFloat() }.toFloat())
        setTranslationY(0.also { translationY = it.toFloat() }.toFloat())
        if (mRotation == 0) {
            originScale = this.height.toFloat() / this.width
            tempScale = originScale
            mRotation = 90
        } else if (mRotation == 90) {
            originScale = 1f
            tempScale = this.width.toFloat() / this.height
            mRotation = 180
        } else if (mRotation == 180) {
            originScale = this.height.toFloat() / this.width
            tempScale = originScale
            mRotation = 270
        } else if (mRotation == 270) {
            originScale = 1f
            tempScale = this.width.toFloat() / this.height
            mRotation = 0
        }
//        Log.d(TAG, "doSetRotation mRotation: "+mRotation);
//        Log.d(TAG, "doSetRotation originScale: "+originScale);
//        Log.d(TAG, "doSetRotation tempScale: "+tempScale);
//        Log.d(TAG, "doSetRotation translationX: "+translationX);
//        Log.d(TAG, "doSetRotation translationY: "+translationY);
//        Log.d(TAG, "doSetRotation getWidth(): "+getWidth());
//        Log.d(TAG, "doSetRotation getHeight(): "+getHeight());
        mScaleFactor = mScaleFactor * tempScale
        checkScaleBound()
        this.rotation = mRotation.toFloat()
        if (setRotationListener != null) {
            setRotationListener!!.setRotation(position, mRotation)
        }
    }
    /**
     * 按照份额系数进行xy的缩放
     */
    fun doSetScaleXY(multiple: Float) {
        mScaleFactor = originScale * multiple
        checkScaleBound()
    }
    /**
     * 对外方法,动态旋转,规则四个视点,逆时针
     */
    fun doSetCCWRotation() {
        var tempScale = 1f
        setTranslationX(0.also { translationX = it.toFloat() }.toFloat())
        setTranslationY(0.also { translationY = it.toFloat() }.toFloat())
        if (mRotation == 0) {
            originScale = this.height.toFloat() / this.width
            tempScale = originScale
            mRotation = 270
        } else if (mRotation == 90) {
            originScale = 1f
            tempScale = this.width.toFloat() / this.height
            mRotation = 0
        } else if (mRotation == 180) {
            originScale = this.height.toFloat() / this.width
            tempScale = originScale
            mRotation = 90
        } else if (mRotation == 270) {
            originScale = 1f
            tempScale = this.width.toFloat() / this.height
            mRotation = 180
        }
//        Log.d(TAG, "doSetRotation mRotation: "+mRotation);
//        Log.d(TAG, "doSetRotation originScale: "+originScale);
//        Log.d(TAG, "doSetRotation tempScale: "+tempScale);
//        Log.d(TAG, "doSetRotation translationX: "+translationX);
//        Log.d(TAG, "doSetRotation translationY: "+translationY);
//        Log.d(TAG, "doSetRotation getWidth(): "+getWidth());
//        Log.d(TAG, "doSetRotation getHeight(): "+getHeight());
        mScaleFactor = mScaleFactor * tempScale
        checkScaleBound()
        this.rotation = mRotation.toFloat()
        if (setRotationListener != null) {
            setRotationListener!!.setRotation(position, mRotation)
        }
    }
    // 触碰两点间间隔
    private fun getSpacing(event: MotionEvent): Float {
        //经过三角函数得到两点间的间隔
        val x = event.getX(0) - event.getX(1)
        val y = event.getY(0) - event.getY(1)
        return Math.sqrt((x * x + y * y).toDouble()).toFloat()
    }
    val bitmap: Bitmap?
        get() {
            val width = this.width
            val height = this.height
            if (height <= 0 || width <= 0) {
                return null
            }
            val mScreenshot = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444)
            val c = Canvas(mScreenshot)
            c.drawFilter = PaintFlagsDrawFilter(
                0,
                Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG
            )
            draw(c)
            return mScreenshot
        }
    fun getmRotation(): Int {
        return mRotation
    }
    fun setAddScale(add: Float) {
//        BigDecimal b1 = new BigDecimal(Float.toString(mScaleFactor));
//        BigDecimal b2 = new BigDecimal(Float.toString(add));
//        float addScale = b1.add(b2).floatValue();
//
//
//        if (addScale > MAX_SCALE) {
//            return;
//        }
        mScaleFactor = mScaleFactor + add * originScale
        checkScaleBound()
        upAnimator(2)
    }
    fun setReduceScale(reduce: Float) {
//        BigDecimal b1 = new BigDecimal(Float.toString(mScaleFactor));
//        BigDecimal b2 = new BigDecimal(Float.toString(reduce));
//        float reduceScale = b1.subtract(b2).floatValue();
//        if (reduceScale < MIN_SCALE) {
//            return;
//        }
        mScaleFactor = mScaleFactor - reduce * originScale
        checkScaleBound()
        upAnimator(2)
    }
     /**
     * 生成bitmap
     */
    fun adjustPhotoRotation(): Bitmap? {
        val bm = bitmap ?: return null
        val m = Matrix()
        m.setRotate(mRotation.toFloat(), bm.width.toFloat() / 2, bm.height.toFloat() / 2)
        try {
            return Bitmap.createBitmap(bm, 0, 0, bm.width, bm.height, m, true)
        } catch (ex: OutOfMemoryError) {
        }
        return null
    }
    /**
     * 双击手势操作
     */
    private inner class CorrectGestureListener : SimpleOnGestureListener() {
        override fun onDoubleTap(e: MotionEvent): Boolean {
            if (isDoing) return super.onDoubleTap(e)
            isDoing = true
            val endFactor: Float
            val scaleCenterX: Float
            val scaleCenterY: Float
            if (mScaleFactor == originScale || mScaleFactor == 1f) {
                scaleCenterX = 0f
                scaleCenterY = 0f
                endFactor = originScale * 2
            } else {
                scaleCenterX = 0f
                scaleCenterY = 0f
                endFactor = originScale
            }
            zoomAnimator(mScaleFactor, endFactor, scaleCenterX, scaleCenterY)
            return super.onDoubleTap(e)
        }
    }
    private fun zoomAnimator(
        startVal: Float,
        endVal: Float,
        scaleCenterX: Float,
        scaleCenterY: Float
    ) {
        if (mScaleAnimator == null) {
            newZoomAnimation()
        }
        if (mScaleAnimator!!.isRunning) {
            return
        }
        val startTranX = translationX
        val startTranY = translationY
        val scaleHolder = PropertyValuesHolder
            .ofFloat(PROPERTY_SCALE, startVal, endVal)
        val tranXHolder = PropertyValuesHolder
            .ofFloat(PROPERTY_TRANX, startTranX, scaleCenterX)
        val tranYHolder = PropertyValuesHolder
            .ofFloat(PROPERTY_TRANY, startTranY, scaleCenterY)
        mScaleAnimator!!.setValues(scaleHolder, tranXHolder, tranYHolder)
        mScaleAnimator!!.duration = DEFAULT_SCALE_DURATION.toLong()
        mScaleAnimator!!.start()
    }
    var mScaleAnimator: ValueAnimator? = null
    /**
     * 缩放动画
     */
    private fun newZoomAnimation() {
        mScaleAnimator = ValueAnimator()
        mScaleAnimator!!.interpolator = DecelerateInterpolator()
        mScaleAnimator!!.addUpdateListener { animation -> //update scaleFactor & tranX & tranY
            val scaleValue = animation.getAnimatedValue(PROPERTY_SCALE) as Float
            val tranXValue = animation.getAnimatedValue(PROPERTY_TRANX) as Float
            val tranYValue = animation.getAnimatedValue(PROPERTY_TRANY) as Float
            //                if (scaleValue<originScale){
//                    mScaleFactor = MIN_SCALE;
//                }else {
            mScaleFactor = scaleValue
            //                }
            scaleX = scaleValue
            scaleY = scaleValue
            setTranslationXY(tranXValue, tranYValue)
        }
        mScaleAnimator!!.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationStart(animation: Animator) {}
            override fun onAnimationEnd(animation: Animator) {
                isDoing = false
            }
            override fun onAnimationCancel(animation: Animator) {}
        })
    }
    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        if (mScaleAnimator != null && mScaleAnimator!!.isRunning) {
            mScaleAnimator!!.cancel()
        }
    }
    interface SetRotationListener {
        fun setRotation(position: Int, rotation: Int)
    }
    private var setRotationListener: SetRotationListener? = null
    fun setSetRotationListener(listener: SetRotationListener?) {
        setRotationListener = listener
    }
    private var position = 0
    fun setPosition(position: Int) {
        this.position = position
    }
    private var tempName //生成需求上传的本地路径,上传成功删除
            : String? = null
    fun setTempName(tempName: String?) {
        this.tempName = tempName
    }
    /**
     * 自己是否不处理
     * true 不处理
     * false 自己处理
     */
    var zoomNotHandler: Boolean? = null
        private set
    init {
        isClickable = true
        init(context)
    }
    companion object {
        private const val DEFAULT_SCALE_DURATION = 300
        private const val PROPERTY_SCALE = "scale"
        private const val PROPERTY_TRANX = "tranX"
        private const val PROPERTY_TRANY = "tranY"
    }
}