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

相关推荐
GitLqr19 小时前
Flutter 无障碍开发实战:玩转 Semantics 解决视障用户使用痛点
android·flutter·dart
雨白1 天前
掌握 NestedScrolling 嵌套滑动:手写仿知乎折叠主页
android
Xzaveir1 天前
别把所有“认证”都塞进 AuthService:实名、一键登录与号码身份的领域拆分
android·人工智能
BerrySen1781 天前
KMP全栈开发:从Android到AI Agent的技术演进与实践
android·人工智能
AFinalStone1 天前
Android 7系统休眠唤醒(一)电源管理架构全景图
android·powermanager·电源管理
YM52e1 天前
鸿蒙Flutter Center居中组件:Align对齐详解
android·学习·flutter·华为·harmonyos·鸿蒙
时间的拾荒人1 天前
MySQL 视图详解
android·数据库·mysql
祉猷并茂,雯华若锦1 天前
Appium 3.x安卓按键与通知栏操作全指南
android·appium
码农coding1 天前
android 12 SurfaceFlinger开机启动分析
android
hunterandroid1 天前
Paging 3 RemoteMediator 实战:构建离线优先的分页列表
android·前端