Android 刮奖效果的实现

作者: lee小杰 | 来源:发表于2016-07-06 16:20 被阅读434次

    先看效果图


    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();
        }
    

    相关文章

      网友评论

        本文标题:Android 刮奖效果的实现

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