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

相关推荐
我就是妖怪6 小时前
KMP全栈开发:从Android到AI Agent的技术演进与实践
android·人工智能
心平气和量大福大7 小时前
android-实例-蒲公英-更新与安装-5-签名与生成APK
android·java·开发语言
阿pin8 小时前
Android随笔-Serializable与Parcelable
android·serializable·parcelable
天空之城--9 小时前
Android 事件分发机制深度解析——原理、源码与实战综合总结
android
阿pin10 小时前
Android随笔-AIDL
android·开发语言·aidl
2501_9160074711 小时前
Bundle ID 注册与管理 App ID 创建指南 命名规则 权限开关与删除注意事项
android·ios·小程序·https·uni-app·iphone·webview
雨白11 小时前
面向对象六大基本原则实战:从零重构支持引擎切换的网络框架
android·架构
张赐荣11 小时前
Android TalkBack 无障碍优化: 为控件自定义转子导航动作
android·microsoft
天空之城--13 小时前
Android Flutter行业动态与学习参考(2026年8月)
android·flutter
quantdash_cc14 小时前
基于 QuantDash 5 分钟 K 线的网格交易策略参数网格搜索寻优实战
android·开发语言·pandas·量化·quantdash