欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android自定义控件(一)——抽奖刮刮乐的实现

程序员文章站 2022-05-29 21:06:00
...

飞来千丈玉蜈蚣,横驾三天白螮蝀,凿开万窍黄云洞。看星低落镜中,月华明秋影玲珑。赑屭金环重,狻猊石柱雄,铁锁囚龙。

今天是小编重回CSDN的第一天,3年没有写过一篇帖子了,这段时间总是给自己找借口忙忙忙,其实就是懒惰而已,所以今天将重新拾起博客,而今天的开篇,就从Android的自定义控件讲起把,为了让大家感兴趣,第一篇就不赘述理论,直接来玩一个有趣的刮刮乐控件。

Android自定义控件(一)——抽奖刮刮乐的实现

众所周知,手机APP中有许多的抽奖方式,比如转盘抽奖,翻牌抽奖等,而今天我们只将刮刮乐抽奖,因为这个在一般网页之中用的还是挺多了,相信以后基本都能用的到。

1.创建自定义View

说到自定义控件当然就需要自定义View来实现刮刮乐,所以选择首先就需要在Android Studio中创建View,实现View常用的三个构造函数,代码如下图所示:

public class ShaveView extends View {
    public ShaveView(Context context) {
        super(context);
    }

    public ShaveView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public ShaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}

其中第二个View构造函数,是我们最常用的,也就是将控件直接写在Layout.xml之中,就会调用此方法,所以我们的初始化工作会在这里进行,不过我们第一步还是要定义成员变量,下面就是用的的成员变量代码:

private float mPreX,mPreY;//刮刮乐手指定位的X,Y坐标
private Bitmap dstBitmap,srcBitmap;//目标图像(手指刮除图层(白色图层)),原图像也就是刮除的灰色图层
private Paint mPaint,mTextPaint;//图像画笔工具,文字画笔工具
private Path mPath;//手指刮除路径
private int strLength;//文字的长度
private int strHeight;//文字的高度
private String textStr="恭喜你中奖了";//刮除后显示的文字

2.初始化控件参数

作为自定义View来说,有一个值得关注的参数,那就是硬件加速,但是有的绘图函数并不支持硬件加速,比如今天小编讲的PorterDuffXfermode,他的部分函数并不支持硬件加速,如果你不知道哪些函数不支持硬件加速,最好关掉硬件加速设置:

setLayerType(LAYER_TYPE_SOFTWARE,null);

接着,我们初始化成员变量,避免后面调用的时候为空,造成空指针错误,代码如下:

this.mPaint=new Paint();
this.mPaint.setColor(Color.RED);//刮刮乐擦除线条颜色
this.mPaint.setStrokeWidth(45);//刮刮乐擦除线宽度
this.mPaint.setStyle(Paint.Style.STROKE);//设置为描边
this.mPath=new Path();
this.mTextPaint=new Paint();
this.mTextPaint.setColor(Color.BLACK);//设置字体颜色
this.mTextPaint.setTextSize(56);//设置字体大小
Rect rect = new Rect();
this.mTextPaint.getTextBounds(textStr,0,textStr.length(),rect);//获取文字的宽高,存储在rect中
this.strLength=rect.width();//获取文字的宽
this.strHeight=rect.height();//获取文字的高

3.onTouchEvent(MotionEvent event)实现

我们是在写一个刮刮乐控件,所以需要捕捉手势操作,而自定义View中的onTouchEvent()就是专门拦截用户手势的,这里我们利用贝济埃曲线将手势连接起来,形成手势轨迹,代码如下:

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()){
        case MotionEvent.ACTION_DOWN:
            mPath.moveTo(event.getX(),event.getY());//贝济埃曲线起点
            this.mPreX=event.getX();
            this.mPreY=event.getY();
            return true;
        case MotionEvent.ACTION_MOVE:
            float endX=(this.mPreX+event.getX())/2;
            float endY=(this.mPreY+event.getY())/2;
            mPath.quadTo(this.mPreX,this.mPreY,endX,endY);//画贝济埃曲线
            this.mPreX=event.getX();
            this.mPreY=event.getY();
            break;
        default:
            break;
    }
    postInvalidate();
    return super.onTouchEvent(event);
}

肯定有人会问什么是贝济埃曲线,这个后续也会将,这里你只需要知道,贝济埃曲线将手指两点之间的线条变得更平滑一些就行。这里代码的意思是,手指记录按下点,然后捕捉移动手指位置,计算得出贝济埃曲线的终点与起始点。

4.OnDraw(Canvas canvas)实现

接着就是画出原图层与目标图层呢?有过PS基础的应该都知道,PS中有一个混合模式,而今天介绍的PorterDuffXfermode也是混合模式,其中有18中混合模式,今天要使用的是PorterDuff.Mode.SRC_OUT混合模式,也就是当目标图层不透明时,计算结果将是透明的,简单的理解就是刮刮乐刮除的区域透明(灰色目标图层与手指刮除图层相交位置透明),也就显示了刮刮乐后面的文字。

理解了混合模式后,我们再来看看onDraw()前面代码:

canvas.drawColor(Color.RED);//设置自定义View背景为白色
if(this.dstBitmap==null || this.srcBitmap==null){//初始化目标图层与源图层
this.srcBitmap=Bitmap.createBitmap(getWidth()/4*3,getHeight()/4*3,Bitmap.Config.ARGB_8888);//源图层,也就是刮刮乐灰色图层
this.dstBitmap=Bitmap.createBitmap(getWidth(),getHeight(),Bitmap.Config.ARGB_8888);//目标图层
this.srcBitmap.eraseColor(Color.GRAY);//设置源图层背景为灰色
}
canvas.drawText(textStr,getWidth()/2-strLength/2,getHeight()/2-strHeight/2,mTextPaint);//画文字

这里我们创建好了两个图层,也可以说是两个图片,比如srcBitmap源图层背景为灰色,同时直接将文字绘制到自定义View的中间位置,而文字的X,Y坐标如下图所示:

Android自定义控件(一)——抽奖刮刮乐的实现

接着就是刮刮乐最核心的代码啦,所以需要认真仔细的看下,代码如下:

int layerId=canvas.saveLayer(0,0,getWidth(),getHeight(),null,Canvas.ALL_SAVE_FLAG);
Canvas c=new Canvas(dstBitmap);//目标图层
c.drawPath(mPath,mPaint);//绘制手指路径

canvas.drawBitmap(dstBitmap,0,0,mPaint);//先画目标图层
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));//设置混合模式
canvas.drawBitmap(srcBitmap,getWidth()/8,getHeight()/8,mPaint);//在画源图层

this.mPaint.setXfermode(null);//设置混合模式为空
canvas.restoreToCount(layerId);

这里我们使用离屏绘制,什么是离屏绘制,后续小编会讲,你现在只需要知道离屏绘制的代码在canvas.save与canvas.restoreToCount中间即可。

其中mPath记录的是手指刮除的位置轨迹,把它先画到dstBitmap目标图层上,然后,根据Xfermode的混合模式,先后画出目标图层与源图层,记住,这个顺序不能变,这个是刮刮乐代码中最核心的代码。

Android自定义控件(一)——抽奖刮刮乐的实现

可能有的小伙伴注意到了,这里小编源图层右上角的坐标为(getWidth()/8,getHeight()/8),这是因为我们使用中,大多数刮刮乐背景边缘并不是灰色,灰色图层在中间显示,所以这里小编将源图层移动到了整个画布的相对中间点的位置,这个可以随意调节,使得看起来更加美观。

代码下载地址:点击下载