Android 刮奖效果的实现

先看效果图


GIF.gif

技术点:

1.画笔的XferMode,XferMode是指定两张图相交后的效果,这里主要是灰色涂层和手指移动痕迹的相交效果。
2.根据onTouchEvent点击事件记录手指移动的坐标,再用这些坐标用drawPath来画出不规则的移动痕迹。

Xfermode

Xfermode有三个子类:

  • AvoidXfermode 指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图)。
  • PixelXorXfermode 当覆盖已有的颜色时,应用一个简单的像素XOR操作。
  • PorterDuffXfermode 有16种规则来控制Paint如何与已有的Canvas图像进行交互,我们用的就是这个。

其中16种规则效果如下图所示,圆为Dst,正方形为Src。

xfermode效果.png
public enum Mode {
    /** [0, 0] */
    CLEAR       (0),
    /** [Sa, Sc] */
    SRC         (1),
    /** [Da, Dc] */
    DST         (2),
    /** [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] */
    SRC_OVER    (3),
    /** [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc] */
    DST_OVER    (4),
    /** [Sa * Da, Sc * Da] */
    SRC_IN      (5),
    /** [Sa * Da, Sa * Dc] */
    DST_IN      (6),
    /** [Sa * (1 - Da), Sc * (1 - Da)] */
    SRC_OUT     (7),
    /** [Da * (1 - Sa), Dc * (1 - Sa)] */
    DST_OUT     (8),
    /** [Da, Sc * Da + (1 - Sa) * Dc] */
    SRC_ATOP    (9),
    /** [Sa, Sa * Dc + Sc * (1 - Da)] */
    DST_ATOP    (10),
    /** [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] */
    XOR         (11),
    /** [Sa + Da - Sa*Da,         Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */
    DARKEN      (16),
    /** [Sa + Da - Sa*Da,         Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */
    LIGHTEN     (17),
    /** [Sa * Da, Sc * Dc] */
    MULTIPLY    (13),
    /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */
    SCREEN      (14),
    /** Saturate(S + D) */
    ADD         (12),
    OVERLAY     (15);

    Mode(int nativeInt) {
        this.nativeInt = nativeInt;
    }
    /**
     * @hide
     */
    public final int nativeInt;
}

RabbleView代码

全部代码都在下面了,其中注释已经说的很清楚了。

public class RabbleView extends TextView{
    //要擦拭的背景
    private Bitmap mBitmap;
    //擦拭背景颜色
    private int bgColor = 0XFFCECECE;
    //擦拭画布
    private Canvas mCanvas;
    //擦拭画笔
    private Paint mPaint;
    //擦拭画笔宽度
    private int mStrokeWidth = DisplayUtils.dp2px(getContext(),40);
    //擦拭痕迹
    private Path mPath;
    private float mX, mY;
    private boolean isUp = false;

    public RabbleView(Context context) {
        this(context,null);
    }

    public RabbleView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public RabbleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initRabble();
    }

    private void initRabble(){
        mPaint = new Paint();
        //透明
        mPaint.setAlpha(0);
        //抗锯齿
        mPaint.setDither(true);
        //防抖动
        mPaint.setAntiAlias(true);
        // 此处不能为透明色
        mPaint.setColor(Color.BLACK);
        //两图的相交模式
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
        mPaint.setStyle(Paint.Style.STROKE);
        //设置结合处的样子,Miter:结合处为锐角, Round:结合处为圆弧:BEVEL:结合处为直线
        mPaint.setStrokeJoin(Paint.Join.ROUND); // 前圆角
        //当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式,如圆形样式
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(mStrokeWidth);
        // 痕迹
        mPath = new Path();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        //初始化擦拭背景
        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
        mCanvas.drawColor(bgColor);
    }

    @Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);
        //要是宽度或者高度为0就没必要加上擦拭涂层了
        if (getWidth() == 0 || getHeight() == 0) {
            return;
        }
        if (!isUp) {
            mCanvas.drawPath(mPath, mPaint);
        } else{
            //当手指离开就把涂层变成透明的
            mBitmap.eraseColor(0X00);
        }
        canvas.drawBitmap(mBitmap, 0, 0, null);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event){
        super.onTouchEvent(event);
        switch (event.getActionMasked()){
            case MotionEvent.ACTION_DOWN:
                down(event.getX(),event.getY());
                break;
            case MotionEvent.ACTION_MOVE:
                move(event.getX(),event.getY());
            break;
            case MotionEvent.ACTION_UP:
                up(event.getX(),event.getY());
                break;
        }
        return true;
    }

    private void down(float x, float y){
        mPath.reset();
        mX = x;
        mY = y;
        mPath.moveTo(x,y);
    }

    private void move(float x, float y){
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= 3 || dy >= 3) {
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
//            mPath.lineTo(x,y);
            mX = x;
            mY = y;
        }
        invalidate();
    }

    private void up(float x, float y){
        mPath.lineTo(x, y);
        mPath.reset();
        isUp = true;
        invalidate();
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容