Android矩阵Matrix动画缩放Bitmap移动手指触点到ImageView中心位置,Kotlin

Android矩阵Matrix动画缩放Bitmap移动手指触点到ImageView中心位置,Kotlin

借鉴 Android双指缩放ScaleGestureDetector检测放大因子大图移动到双指中心点ImageView区域中心,Kotlin(2)-CSDN博客 在此基础上实现手指在屏幕上点击后,动画放大图片,在放大过程中,移动手指触点位置到ImageView的中心。

Kotlin 复制代码
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.RectF
import android.graphics.drawable.BitmapDrawable
import android.os.Bundle
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatImageView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

class MyImageView : AppCompatImageView {
    private var mCurX = 0f
    private var mCurY = 0f
    private var mCanDrawBitmap = false

    private var W = 0
    private var H = 0

    private val SCALE_FACTOR: Float = 5.5f
    private var mOriginBmp: Bitmap? = null

    private var mCirclePaint = Paint()

    private var mDeltaScaleFactor: Float = 0f
    private var mAnimScaleBmp: Bitmap? = null

    private var mCanDrawTouchPoint = false
    private var mTouchPointX = 0f
    private var mTouchPointY = 0f

    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) {
        mCirclePaint.style = Paint.Style.STROKE
        mCirclePaint.strokeWidth = 10f
        mCirclePaint.isAntiAlias = true
        mCirclePaint.color = Color.RED

        mOriginBmp = (this.drawable as BitmapDrawable).bitmap
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)

        W = w
        H = h
        Log.d("fly", "W=$W H=$H")
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        if (event == null) {
            return false
        }

        mCurX = event.x
        mCurY = event.y

        when (event.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                //启动动画。
                startScaleAnim()
            }
        }

        return false
    }

    /**
     * Bitmap.createScaledBitmap耗时加剧卡顿。
     * 优化方案,基于原图setRectToRect缩放到给定宽w高h的放大图。
     */
    private fun getScaleBmp(w: Int, h: Int): Bitmap {
        val bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
        val c = Canvas(bmp)
        c.drawColor(Color.BLUE)

        val src = RectF(0f, 0f, mOriginBmp!!.width.toFloat(), mOriginBmp!!.height.toFloat())
        val dst = RectF(0f, 0f, w.toFloat(), h.toFloat())
        val mx = Matrix()
        mx.setRectToRect(src, dst, Matrix.ScaleToFit.CENTER)
        c.drawBitmap(mOriginBmp!!, mx, null)

        return bmp
    }

    private fun startScaleAnim() {
        val step = 50f //经过step后,完成缩放动画。
        val delta = (SCALE_FACTOR - 1) / step

        CoroutineScope(Dispatchers.IO).launch {
            //绘制在原图上手的触点。
            mTouchPointX = mCurX
            mTouchPointY = mCurY
            mCanDrawTouchPoint = true
            myPostInvalidate()
            delay(500) //延时,观察手指触点。
            mCanDrawTouchPoint = false


            mCanDrawBitmap = true
            for (i in 0 until step.toInt()) {
                mDeltaScaleFactor = 1f + delta * i

                /*
                mAnimScaleBmp = Bitmap.createScaledBitmap(
                    mOriginBmp!!,
                    (W * mDeltaScaleFactor + 1).toInt(), //注意精度损失,造成坐标偏移。
                    (H * mDeltaScaleFactor + 1).toInt(),//注意精度损失,造成坐标偏移。
                    true
                )
                 */
                mAnimScaleBmp = getScaleBmp((W * mDeltaScaleFactor + 0.5).toInt(), (H * mDeltaScaleFactor + 0.5).toInt())

                //触发重绘。
                myPostInvalidate()
            }


            //for循环完成后,绘制最终图片动画放大完成后的中心圆点。
            mTouchPointX = W / 2f
            mTouchPointY = H / 2f
            mCanDrawTouchPoint = true
            myPostInvalidate()
        }
    }

    private fun myPostInvalidate() {
        this.postInvalidate()
    }

    private fun drawTouchPoint(c: Canvas) {
        c.drawCircle(mTouchPointX, mTouchPointY, 50f, mCirclePaint)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        if (mCanDrawBitmap) {
            val mx = Matrix()
            mx.setScale(mDeltaScaleFactor, mDeltaScaleFactor)
            mx.setTranslate(W / 2f - mCurX * mDeltaScaleFactor, H / 2f - mCurY * mDeltaScaleFactor)
            canvas.drawBitmap(mAnimScaleBmp!!, mx, null)
        }

        if (mCanDrawTouchPoint) {
            drawTouchPoint(canvas)
        }
    }
}

Android双指缩放ScaleGestureDetector检测放大因子大图移动到双指中心点ImageView区域中心,Kotlin(2)-CSDN博客文章浏览阅读613次,点赞4次,收藏5次。需要注意的,因为在xml布局里面特别设置了ImageView的高度为wrap_content,手指在屏幕触点的位置是放大镜里面放大图片后准确圆心位置,但是,如果ImageView设置成match_parent,则因为ImageView里面的Bitmap被缩放(此处Bitmap其实小于ImageView,被拉伸了),拉伸后的Bitmap水平方向坐标与ImageView一直重合,但竖直方向,Bitmap坐标与ImageView不一致,会造成一种现象,手指触点放大镜放大后,水平方向是正确的,但竖直方向有偏移量。https://blog.csdn.net/zhangphil/article/details/135701608Android矩阵setRectToRect裁剪Bitmap原图Matrix放大,mapRect标记中心区域,Kotlin-CSDN博客文章浏览阅读229次,点赞3次,收藏5次。【代码】Android矩阵setRectToRect裁剪Bitmap原图Matrix放大,mapRect标记中心区域,Kotlin。https://blog.csdn.net/zhangphil/article/details/135960921

Android ScaleGestureDetector检测双指缩放Bitmap基于Matrix动画移动到双指捏合中心点ImageView区域中心,Kotlin_android的两指捏合-CSDN博客文章浏览阅读256次,点赞5次,收藏11次。需要注意的,因为在xml布局里面特别设置了ImageView的高度为wrap_content,手指在屏幕触点的位置是放大镜里面放大图片后准确圆心位置,但是,如果ImageView设置成match_parent,则因为ImageView里面的Bitmap被缩放(此处Bitmap其实小于ImageView,被拉伸了),拉伸后的Bitmap水平方向坐标与ImageView一直重合,但竖直方向,Bitmap坐标与ImageView不一致,会造成一种现象,手指触点放大镜放大后,水平方向是正确的,但竖直方向有偏移量。_android的两指捏合https://blog.csdn.net/zhangphil/article/details/135705931

相关推荐
机智的张尼玛10 小时前
我基于 Kotlin Multiplatform 实现了一套跨平台的弱网离线同步引擎
android·开源·kotlin
安卓修改大师13 小时前
安卓修改大师反编译引擎Apktool深度解析:版本选择、参数说明与实战技巧
android
error:(13 小时前
【系统与实战双精通】VS Code 调试 ROS2 Python 节点与 Launch 系统指南
android·java·python
我是唐青枫14 小时前
Kotlin 运算符重载详解:为什么 a += b 有时改对象,有时换对象?
开发语言·kotlin
黄林晴15 小时前
Kuikly 是什么?和KMP有什么关系?
android·前端
帅次16 小时前
Android 高级工程师面试:Kotlin 语法基础 近1年高频追问 22 题
android·面试·kotlin·扩展函数·空安全
想你依然心痛17 小时前
嵌入式日志系统:分级日志、环形缓冲区与远程输出——运行时调试、非侵入
android·前端·javascript
用户693717500138418 小时前
AI Agent 里的 Loop 到底是什么?
android·前端·后端
海天鹰18 小时前
安卓分割空字符串数组长度为1
android
Coffeeee19 小时前
从 Android 15 到 Android 17,谷歌猝不及防的音频改动
android·前端·google