美文网首页
Android自定义View(11) 《实现一个刮刮乐抽奖效果》

Android自定义View(11) 《实现一个刮刮乐抽奖效果》

作者: 非典型程序猿 | 来源:发表于2021-09-08 23:27 被阅读0次

概述

今天回来看书突然看到了一个很有意思的效果,就立马动手写了一下,结合贝塞尔曲线简介中捕捉手指路径的示例,我就继续敲了一下~话不多说,我们先来看效果

运行结果

图像有点大~耐心等待一下哦


ezgif.com-gif-maker.gif

最喜欢的两个新疆美女~

PorterDuff.Mode.SRC_OUT

这里我们主要用到了混合模式中的PorterDuff.Mode.SRC_OUT,因为混合模式比较多,等全部了解之后会写一篇完整的混合模式介绍,这里我们只介绍这个模式下的效果
SRC_OUT的特性可以概括为,这里我们把带有Path的空白Bitmap称为目标图像,迪丽热巴的图像称为源图像,当目标图像有图像时结果显示空白像素,当目标图像没有图像结果时显示源图像。因此这个效果用来作为橡皮擦效果是最完美不过了~利用该特性我们开始进行动手写代码

绘制步骤

  • 首先我们需要准备好两张美女的图片
  • 绘制底层的图片 - 哈尼克孜
  • 调用saveLayer()保存图层状态并新增一个画布
  • 新画布上绘制一个空白的带有Path路径的Bitmap
  • 计算源图像区域,用画笔的混合模式中的SRC_OUT模式绘制出迪丽热巴的照片

简单来说,就是我们先绘制一张哈尼的图片,然后作为透明图层保存下来并创建一个新画布,接着在这个新画布上绘制一个空白的Bitmap,再绘制Path路径,最后在这个画布上利用混合模式绘制迪丽热巴的图片

  • 从下至上依次为
  1. 带有哈尼克孜的画布
  2. 绘制有空白的带有Path的Bitmap和迪丽热巴图像混合模式的画布

当目标图像(绘制了路径的新建的Bitmap图像)有图像时结果显示空白像素(被path绘制到的部分,显示出了下层画布哈尼的图像) , 当目标图像(热巴的图像)没有图像结果时(没有被我们用path绘制过的部分)显示源图像(迪丽热巴的图像)。

上源码

package com.tx.camera.view

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import com.tx.camera.R

/**
 * create by xu.tian
 * @date 2021/9/7
 */
class BezierView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
    var paint : Paint = Paint()

    var bitmapBg = BitmapFactory.decodeResource(resources, R.drawable.hanikezi)
    var bitmapSrc = BitmapFactory.decodeResource(resources, R.drawable.dilireba)
    var bitmapDst = Bitmap.createBitmap(bitmapSrc.width,bitmapSrc.height,Bitmap.Config.ARGB_8888)
    var w = 0
    var h = 0
    init {
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = 100f
        setLayerType(LAYER_TYPE_SOFTWARE,null)
    }

    var preX = 0f
    var preY = 0f
    var path = Path()

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        // 绘制底层图片
        canvas?.drawBitmap(bitmapBg,null,Rect(0,0,bitmapDst.width,bitmapDst.height),paint)

        var layerId : Int = canvas?.saveLayer(0f,0f, w.toFloat(), h.toFloat(),null,Canvas.ALL_SAVE_FLAG)!!
        // 把手势路径绘制到目标图像上
        var c = Canvas(bitmapDst)
        c.drawPath(path,paint)

        // 把目标图像绘制到画布上
        canvas?.drawBitmap(bitmapDst,0f,0f,paint)

        // 计算源图像区域
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_OUT)
        canvas?.drawBitmap(bitmapSrc,0f,0f,paint)
        // 取消混合模式
        paint.xfermode = null
        // 恢复画布状态
        canvas?.restoreToCount(layerId)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when (event?.action){
            MotionEvent.ACTION_DOWN -> actionDown(event)
            MotionEvent.ACTION_MOVE -> bezierPathMove(event)
        }
        return true
    }

    private fun actionDown(event: MotionEvent){
        preX = event.x
        preY = event.y
        path.moveTo(preX,preY)
    }

    private fun linePathMove(event: MotionEvent){
        path.lineTo(event.x,event.y)
        postInvalidate()
    }

    private fun bezierPathMove(event: MotionEvent){
        path.quadTo(preX,preY,(event.x+preX)/2,(event.y+preY)/2)
        preX = event.x
        preY = event.y
        postInvalidate()
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        this.w = w
        this.h = h
    }
}

saveLayer()方法

这里简单说一下,这个方法可以保存当前的绘制内容且会生成一个新的Canvas,调用这个函数后的绘制过程都会在这个Canvas上进行。在这个例子中,我们的保存路径的bitmap和迪丽热巴的图像就在同一个canvas中~

总结

今天有点小累~就写到这里了

相关文章

网友评论

      本文标题:Android自定义View(11) 《实现一个刮刮乐抽奖效果》

      本文链接:https://www.haomeiwen.com/subject/ybjbwltx.html