先上效果:
刮刮乐
class EraseView : View {private val mPaint by lazy {Paint().apply {color = Color.REDisAntiAlias = truestrokeWidth = 50f // 设置画笔粗细style = Paint.Style.STROKE // 设置画笔样式为描边strokeCap = Paint.Cap.ROUND // 设置画笔端点为圆形strokeJoin = Paint.Join.ROUND // 设置拐角为圆形}}private val mTextPaint by lazy {Paint().apply {isAntiAlias = truecolor = Color.RED // 设置擦除画笔为红色style = Paint.Style.FILL // 设置画笔样式为描边strokeWidth = 50f// 设置画笔粗细strokeCap = Paint.Cap.ROUND // 设置画笔端点为圆形strokeJoin = Paint.Join.ROUND // 设置拐角为圆形textSize = 44f}}private val mPath = Path()// 源图像private lateinit var srcBitmap: Bitmap// 目标图层private lateinit var dstBitmap: Bitmapprivate var showText = ""//文案private var isShowResultDirect = false//是否直接展示结果constructor(context: Context?) : this(context, null)constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context,attrs,defStyleAttr)init {showText = getRandomStr()}override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {// 初始化图片资源val originBitmap = BitmapFactory.decodeResource(resources, R.drawable.image_convor)srcBitmap = Bitmap.createScaledBitmap(originBitmap, w, h, false)dstBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)}@SuppressLint("DrawAllocation")override fun onDraw(canvas: Canvas) {super.onDraw(canvas)if (!this::srcBitmap.isInitialized || !this::dstBitmap.isInitialized) returnkotlin.runCatching {canvas.drawColor(Color.parseColor("#BBBBBB"))}val textWidth = mTextPaint.measureText(showText) //文本宽度val fontMetrics = mTextPaint.fontMetricsval baselineOffset = (fontMetrics.bottom + fontMetrics.top) / 2//显示的文案居中绘制canvas.drawText(showText,(width - textWidth) / 2f,height / 2f - baselineOffset,mTextPaint)val layerId = canvas.saveLayer(0f, 0f, width.toFloat(), height.toFloat(), null)// 1. 在画布上绘制擦除路径canvas.drawPath(mPath, mPaint)// 2. 绘制背景图像(目标图像)canvas.drawBitmap(dstBitmap, 0f, 0f, mPaint)// 3. 手动擦除,设置混合模式为 SRC_OUT,实现擦除效果;直接展示结果,用DST_OUTmPaint.xfermode =PorterDuffXfermode(if (isShowResultDirect) PorterDuff.Mode.DST_OUT else PorterDuff.Mode.SRC_OUT)canvas.drawBitmap(srcBitmap, 0f, 0f, mPaint)mPaint.xfermode = nullcanvas.restoreToCount(layerId)}// 处理触摸事件,动态更新擦除路径override fun onTouchEvent(event: MotionEvent): Boolean {val x = event.xval y = event.ywhen (event.action) {MotionEvent.ACTION_DOWN -> {// 请求父视图不要拦截事件parent.requestDisallowInterceptTouchEvent(true)mPath.moveTo(x, y) // 路径起点}MotionEvent.ACTION_MOVE -> {mPath.lineTo(x, y) // 路径延续invalidate() // 重新绘制}MotionEvent.ACTION_UP -> {parent.requestDisallowInterceptTouchEvent(false)}}return true}/*** 重置文案*/private fun getRandomStr(): String {return listOf("谢谢惠顾", "特等奖", "一等奖", "二等奖", "三等奖").random()}/*** 重置状态,再刮一次*/fun resetState() {mPath.reset()isShowResultDirect = falseshowText = getRandomStr()invalidate()}/*** 直接展示结果*/fun showResultDirect() {isShowResultDirect = trueinvalidate()}
}