Android Matrix剪切clipPath缩放scale图片postTranslate圆形放大镜,Kotlin(1)

Android Matrix剪切clipPath缩放scale图片postTranslate圆形放大镜,Kotlin(1)

实现查看图片的放大镜,放大镜随着手指在屏幕上的移动,放大镜里面展示手指触点为中心、半径长度的圆形放大后的图片。

剪切出一块圆形Path,然后在圆形Path画放大后的图。因为是clipPath,只会显示Path区域内,区域外不显示。

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.Path
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


class MainActivity : AppCompatActivity() {
    private var image: MyImage? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        image = findViewById(R.id.image)
    }
}

class MyImage : AppCompatImageView {
    private val TAG = "fly"

    private var mIsDraw = false
    private var curX: Float = 0f
    private var curY: Float = 0f

    private var originBmp: Bitmap = (drawable as BitmapDrawable).bitmap

    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when (event?.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                mIsDraw = true

                curX = event.x
                curY = event.y

                invalidate()
            }

            MotionEvent.ACTION_MOVE -> {
                curX = event.x
                curY = event.y

                invalidate()
            }

            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                mIsDraw = false

                invalidate()
            }
        }

        return true
    }

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

        if (canDraw()) {
            myDraw(canvas)
        }
    }

    private fun canDraw(): Boolean {
        return mIsDraw
    }

    /**
     * Matrix放大矩阵,然后通过clipPath剪切一块圆形区域作为放大镜区域,然后直接在clipPath的区域上绘制放大后的图。
     */
    private fun myDraw(canvas: Canvas) {
        Log.d(TAG, "ImageView w=${width} h=${height} Bitmap w=${originBmp.width} h=${originBmp.height}")

        val path = Path()
        val radius = 250f
        val factor = 2f

        val paint = Paint(Paint.ANTI_ALIAS_FLAG)
        paint.color = Color.RED
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = 10f

        path.addCircle(curX, curY, radius, Path.Direction.CW)
        canvas.drawPath(path, paint) //画红色的圆圈,圆心是手指在屏幕上的触点。

        canvas.clipPath(path) //剪切出来一片圆形区域。

        //特别注意,这里固定以手机屏幕的宽度为基准等比例放大Bitmap。
        val scaleW: Float = resources.displayMetrics.widthPixels.toFloat()
        val scaleH: Float = (originBmp.height.toFloat() / originBmp.width.toFloat()) * scaleW
        Log.d(TAG, "display w=${scaleW} h=${scaleH}")

        val matrix = Matrix()
        matrix.setScale(factor, factor)
        //canvas.concat(matrix)

        val dx = -curX * (factor - 1)
        val dy = -curY * (factor - 1)
        //上下左右移动矩阵,使得放大后的矩阵处于圆圈的内容刚好是手指触点为中心的圆图。
        matrix.postTranslate(dx, dy)

        canvas.drawBitmap(
            Bitmap.createScaledBitmap(originBmp, scaleW.toInt(), scaleH.toInt(), true),
            matrix,
            paint
        )
    }
}
XML 复制代码
    <com.pkg.MyImage
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:scaleType="fitCenter"
        android:src="@mipmap/p2" />

需要注意的,因为在xml布局里面特别设置了ImageView的高度为wrap_content,手指在屏幕触点的位置是放大镜里面放大图片后准确圆心位置,但是,如果ImageView设置成match_parent,则因为ImageView里面的Bitmap被缩放(此处Bitmap其实小于ImageView,被拉伸了),拉伸后的Bitmap水平方向坐标与ImageView一直重合,但竖直方向,Bitmap坐标与ImageView不一致,会造成一种现象,手指触点放大镜放大后,水平方向是正确的,但竖直方向有偏移量。如果想要纠正竖直方向的偏移量,可以考虑调校Bitmap竖直方向顶部与ImageView顶部的坐标偏移。

Android Matrix画布Canvas缩放scale,Kotlin-CSDN博客文章浏览阅读168次,点赞3次,收藏3次。文章浏览阅读9.6k次。文章浏览阅读1.8k次。/*Java代码 将Drawable转化为Bitmap */ Bitmap drawableToBitmap(Drawable drawable) { int width = drawable.getIntrinsicWidth();Android Material Design :LinearLayoutCompat添加分割线divider_linearlayout 分割线-CSDN博客。https://blog.csdn.net/zhangphil/article/details/135114661

相关推荐
冬奇Lab1 天前
PMS核心机制:应用安装与包管理深度解析
android·源码阅读
城东米粉儿1 天前
Android 计算滑动帧率 笔记
android
城东米粉儿1 天前
Android Choreographer 和 looper 结合使用 监控
android
城东米粉儿1 天前
Android inline Hook 笔记
android
城东米粉儿1 天前
Android 防止 Printer 覆盖笔记
android
Android系统攻城狮1 天前
Android tinyalsa深度解析之pcm_get_timestamp调用流程与实战(一百一十八)
android·pcm·tinyalsa·android hal·audio hal
yuezhilangniao1 天前
win10环境变量完全指南:Java、Maven、Android、Flutter -含我的环境备份
android·java·maven
奔跑吧 android1 天前
【车载Audio】【AudioHal 06】【高通音频架构】【深入浅出 Android Audio HAL:从加载到函数指针绑定的全链路解析】
android·音视频·audioflinger·aosp13·8295·audiohal·高通音频架构
无巧不成书02181 天前
Kotlin Multiplatform (KMP) 鸿蒙开发整合实战|2026最新方案
android·开发语言·kotlin·harmonyos·kmp