Android Matrix绘制PaintDrawable设置BitmapShader,手指触点为圆心scale放大原图,Kotlin(二)
在 Android Matrix绘制PaintDrawable设置BitmapShader,手指触点为圆心scale放大原图,Kotlin-CSDN博客 基础上,限定下面切图的绘制区域,超出绿色区域的轨迹线不再绘制。
Kotlin
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapShader
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.Path
import android.graphics.RectF
import android.graphics.Shader.TileMode
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.PaintDrawable
import android.os.Bundle
import android.util.AttributeSet
import android.view.MotionEvent
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatImageView
class MainActivity : AppCompatActivity() {
private var iv: MyImageView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
iv = findViewById(R.id.iv)
val r = findViewById<ImageView>(R.id.result)
iv?.setTestImageView(r)
}
}
class MyImageView : AppCompatImageView {
private var mCurX = 0f
private var mCurY = 0f
private val mPath1 = Path()
private val mPath2 = Path()
private val mPathPaint1 = Paint()
private val mPathPaint2 = Paint()
private val mPathPaint3 = Paint()
private val mCirclePaint = Paint()
private var mNewBmp: Bitmap? = null
private var mSrcBmp: Bitmap? = null
private var mIsDraw = false
private val mRadius = 380f
private var mDrawable: PaintDrawable? = null
private var testIV: ImageView? = null
//放大系数。
private val mScaleFactor = 2.6f
private var mBitmapShader: BitmapShader? = null
constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) {
mSrcBmp = (drawable as BitmapDrawable).bitmap //mSrcBmp是原始图大小,没有缩放和拉伸的。
mPathPaint1.style = Paint.Style.STROKE
mPathPaint1.strokeWidth = 10f
mPathPaint1.isAntiAlias = true
mPathPaint1.color = Color.RED
mPathPaint2.style = Paint.Style.STROKE
mPathPaint2.strokeWidth = 25f
mPathPaint2.isAntiAlias = true
mPathPaint2.color = Color.YELLOW
mPathPaint3.style = Paint.Style.STROKE
mPathPaint3.strokeWidth = 3f
mPathPaint3.isAntiAlias = true
mPathPaint3.color = Color.GREEN
mCirclePaint.style = Paint.Style.STROKE
mCirclePaint.strokeWidth = 30f
mCirclePaint.isAntiAlias = true
mCirclePaint.color = Color.BLUE
}
fun setTestImageView(iv: ImageView?) {
testIV = iv
}
override fun onTouchEvent(event: MotionEvent): Boolean {
mCurX = event.x
mCurY = event.y
when (event.action) {
MotionEvent.ACTION_DOWN -> {
mPath1.moveTo(mCurX, mCurY)
mPath2.moveTo(mCurX * mScaleFactor, mCurY * mScaleFactor)
mIsDraw = true
}
MotionEvent.ACTION_MOVE -> {
mPath1.lineTo(mCurX, mCurY)
mPath2.lineTo(mCurX * mScaleFactor, mCurY * mScaleFactor)
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
mIsDraw = false
//抬手后,清除手指轨迹。
myClear()
}
}
invalidate()
return true
}
private fun myClear() {
//清除历史轨迹。
mPath1.reset()
mPath2.reset()
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
if (mIsDraw) {
myDraw()
canvas.drawPath(mPath1, mPathPaint1)
}
}
private fun myDraw() {
if (mBitmapShader == null) {
//创建一次,避免重复创建,提高速度。
mBitmapShader = BitmapShader(
Bitmap.createScaledBitmap(
mSrcBmp!!,
(this.width * mScaleFactor).toInt(), //注意这里的如果精度损失,会造成坐标偏移
(this.height * mScaleFactor).toInt(),//注意这里的如果精度损失,会造成坐标偏移
true
),
TileMode.DECAL,
TileMode.DECAL
)
}
if (mDrawable == null) {
//创建一次,避免重复创建,提高速度。
mDrawable = PaintDrawable(Color.BLACK)
mDrawable!!.setCornerRadius(mRadius / 2) //圆角矩形,如果不除2即是圆形框图。
mDrawable!!.paint.shader = mBitmapShader
mDrawable!!.setBounds(0, 0, (mRadius * 2).toInt(), (mRadius * 2).toInt())
}
if (mNewBmp == null) {
//创建一次,避免重复创建,提高速度。
mNewBmp = Bitmap.createBitmap(this.width, this.height, Bitmap.Config.ARGB_8888)
}
val c = Canvas(mNewBmp!!)
c.drawColor(Color.GRAY) //底色。
val matrix = Matrix()
matrix.setScale(mScaleFactor, mScaleFactor)
matrix.setTranslate((-mCurX) * mScaleFactor + mRadius, (-mCurY) * mScaleFactor + mRadius)
mDrawable!!.paint.shader.setLocalMatrix(matrix)
mDrawable!!.draw(c)
val rectF = RectF()
matrix.mapRect(rectF)
val cx = mCurX * mScaleFactor + rectF.left
val cy = mCurY * mScaleFactor + rectF.top
//蓝色中心圆圈
c.drawCircle(cx, cy, 50f, mCirclePaint)
//绿色圆角矩形框。
val roundRectPath = Path()
val roundRectF = RectF(cx - 250, cy - 250, cy + 250, cy + 250)
roundRectPath.addRoundRect(roundRectF, 25f, 25f, Path.Direction.CW)
c.drawPath(roundRectPath, mPathPaint3)
//限定下面切图中Path绘制轨迹路线的区域,超出边界不绘制。
c.clipRect(roundRectF)
//下面小框图里面的Path
val path = Path()
mPath2.transform(matrix, path)
//绘制下面框图里面的Path
c.drawPath(path, mPathPaint2)
testIV?.setImageBitmap(mNewBmp)
}
}
XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/darker_gray"
android:orientation="vertical"
tools:context=".MainActivity">
<com.pkg.MyImageView
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:background="@drawable/ic_launcher_background"
android:scaleType="fitCenter"
android:src="@mipmap/mypic" />
<ImageView
android:id="@+id/result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:background="@drawable/ic_launcher_background"
android:src="@drawable/ic_launcher_foreground" />
</LinearLayout>
所有的绘制轨迹线,都限定在了绿色的圆角矩形框中,超出区域不予绘制。
遗留问题,手指在上图滑动过程中,当滑动到一定区域,下面的切图框中已无太有效的图可以"放大",后续可以填充黑色,表示无效放大。