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

相关推荐
是阿建吖!7 分钟前
【Linux】信号
android·linux·c语言·c++
alexhilton2 小时前
AppFunctions:让你的Android应用更容易被AI智能体发现
android·kotlin·android jetpack
qq3621967052 小时前
APK文件签名校验教程:验证APK真伪的完整方法
android·智能手机
赏金术士2 小时前
Android 组件化概念和特征
android·kotlin·组件化
2501_915909069 小时前
深入解析Mock.js:功能、应用及实战案例,提升前端开发效率
android·ios·小程序·https·uni-app·iphone·webview
流星白龙10 小时前
【MySQL高阶】21.撤销表空间,撤销日志
android·mysql·adb
我命由我1234511 小时前
Android 开发,FragmentPagerAdapter 的 isViewFromObject 方法问题
android·java-ee·kotlin·android studio·android jetpack·android-studio·android runtime
weiggle11 小时前
第五篇:Modifier 解析——链式调用的艺术
android
awu的Android笔记12 小时前
Android 弱网模拟:别只会用均匀分布——三种延迟模型和两种丢包模型的原理与实现
android·tcp/ip