Android - 刮刮卡

参考转载至 慕课网 《Android电商活动中的刮刮卡 http://www.imooc.com/view/225》

1、获取canvas 的两种途径

  1)onDraw(Canvas canvas); 该回调方法由系统传参

  2)new Canvan(mBitmap);

     mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
        mCanvas.drawBitmap(mOverlayBitmap,null,new Rect(0,0,getWidth(),getHeight()),null);

2、实现刮刮卡刮涂效果

  paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 

  Dst = 遮盖层,Src = 刮涂路径,DstOut 模式下刮涂路径的像素点值为零;

  

3、获取图片像素:bitmap.getPixels();

4、自定义View属性

  1)values/attr.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="text" format="string"></attr>
    <attr name="textColor" format="color"></attr>
    <attr name="textSize" format="dimension"></attr>

    <declare-styleable name="GuaGuaKa">
        <attr name="text"></attr>
        <attr name="textColor"></attr>
        <attr name="textSize"></attr>
    </declare-styleable>
</resources>

  2) 获取自定义属性

    private String mText;    //中奖信息文本
    private int mTextColor;  //中奖信息文本颜色
    private int mTextSize;   //中奖信息文本大小

     TypedArray a = null;
        a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.GuaGuaKa, defStyleAttr, 0);
        int n = a.getIndexCount();
        for (int i = 0; i < n; i++) {
            int attr = a.getIndex(i);
            switch (attr) {
                case R.styleable.GuaGuaKa_text:
                    mText = a.getString(attr);
                    break;
                case R.styleable.GuaGuaKa_textColor:
                    mTextColor = a.getColor(attr, 0x000000);
                    break;
                case R.styleable.GuaGuaKa_textSize:
                    mTextSize = (int) a.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 22, getResources().getDisplayMetrics()));
                    break;
            }
        }
        if (a != null) a.recycle();

5、完整代码

public class GuaGuaKa extends View {

    /*
            自定义View属性
     */
    private String mText;    //中奖信息文本
    private int mTextColor;  //中奖信息文本颜色
    private int mTextSize;   //中奖信息文本大小


    private Paint mTextPaint;  //中奖信息画笔
    private Paint mBrushPaint; //刮涂效果画笔
    private Bitmap mBitmap;    //刮涂效果图片
    private Canvas mCanvas;    //刮涂效果画布
    private Rect mTextBound;   //中奖信息文字区块
    private Path mPath;        //刮涂效果路径
    private Bitmap mOverlayBitmap; //遮盖层图片
    private float mLastX, mLastY;
    private boolean mHasCompleted = false; //刮涂达到预定值既完成

    /*
        刮涂完成回调接口
     */
    public interface OnCompletedListener {
        void OnCompleted(String text);
    }

    private OnCompletedListener mOnCompletedListener;

    public void setOnCompletedListener(OnCompletedListener listener) {
        this.mOnCompletedListener = listener;
    }

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

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

    public GuaGuaKa(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        init(); //初始化

        TypedArray a = null;
        a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.GuaGuaKa, defStyleAttr, 0);
        int n = a.getIndexCount();
        for (int i = 0; i < n; i++) {
            int attr = a.getIndex(i);
            switch (attr) {
                case R.styleable.GuaGuaKa_text:
                    mText = a.getString(attr);
                    break;
                case R.styleable.GuaGuaKa_textColor:
                    mTextColor = a.getColor(attr, 0x000000);
                    break;
                case R.styleable.GuaGuaKa_textSize:
                    mTextSize = (int) a.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 22, getResources().getDisplayMetrics()));
                    break;
            }
        }
        if (a != null) a.recycle();
    }


    private void init(){
        mText="谢谢惠顾";
        mTextBound=new Rect();
        mTextSize=(int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,22,getResources().getDisplayMetrics());

        mTextPaint=new Paint();
        mBrushPaint=new Paint();
        mPath=new Path();
        mOverlayBitmap=BitmapFactory.decodeResource(getResources(),R.drawable.fg_guaguaka);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        setUpTextPaint();
        setUpOverlayPaint();
    }

    /*
        设置绘制中奖信息所需对象
     */
    private void setUpTextPaint() {
        mTextPaint.setAntiAlias(true);
        mTextPaint.setStyle(Paint.Style.STROKE);
        mTextPaint.setTextSize(mTextSize);
        mTextPaint.setColor(mTextColor);

        //获得当前画笔绘制文本的宽与高
        mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBound);
    }

    /*
        设置绘制遮盖层所需对象
     */
    private void setUpOverlayPaint() {
        mBrushPaint.setAntiAlias(true);
        mBrushPaint.setDither(true);
        mBrushPaint.setStrokeJoin(Paint.Join.ROUND);
        mBrushPaint.setStrokeCap(Paint.Cap.ROUND);
        mBrushPaint.setStyle(Paint.Style.FILL);
        mBrushPaint.setStrokeWidth(20);

        mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
        mCanvas.drawBitmap(mOverlayBitmap,null,new Rect(0,0,getWidth(),getHeight()),null);
        mPath = new Path();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mPath.moveTo(x, y);
                mLastX = x;
                mLastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                float dx = Math.abs(x - mLastX);
                float dy = Math.abs(y - mLastY);
                if (dx > 3.0f || dy > 3.0f) {
                    mPath.lineTo(x, y);
                }
                mLastX = x;
                mLastY = y;
                break;
            case MotionEvent.ACTION_UP:
                if (!mHasCompleted) {
                    if (calculateCompletedPercent() >= 60) {
                        mHasCompleted = true;
                        postInvalidate();
                        //完成后回调
                        if (mOnCompletedListener != null) {
                            mOnCompletedListener.OnCompleted(mText);
                        }
                    }
                }
                break;
            default:
                return super.onTouchEvent(event);
        }
        if (!mHasCompleted) {
            postInvalidate();
        }
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {

        //绘制中奖信息文本
        canvas.drawRect(10, 10, getWidth() - 10, getHeight() - 10, mTextPaint);
        canvas.translate(getWidth() / 2, getHeight() / 2);
        canvas.drawText(mText, -mTextBound.width() / 2, mTextBound.height() / 2, mTextPaint);
        canvas.translate(-getWidth() / 2, -getHeight() / 2);

        if (!mHasCompleted) {
            //设置画笔刮涂效果
            mBrushPaint.setStyle(Paint.Style.STROKE);
            mBrushPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
            //绘制刮涂路径
            mCanvas.drawPath(mPath, mBrushPaint);
            canvas.drawBitmap(mBitmap, 0, 0, null);
        }
    }

    /*
        计算刮涂完成百分比
     */
    private int calculateCompletedPercent() {
        int w = mBitmap.getWidth();
        int h = mBitmap.getHeight();

        float wipeArea = 0;    //被擦除的像素
        float totalArea = w * h; //所有像素

        int percent = 0;

        int[] pixels = new int[w * h];
        //获得bitmap上所有像素信息
        mBitmap.getPixels(pixels, 0, w, 0, 0, w, h);
        for (int i = 0; i < w; i++) {
            for (int j = 0; j < h; j++) {
                int index = j * w + i;
                if (pixels[index] == 0) {
                    wipeArea++;
                }
            }
        }

        if (wipeArea > 0 && totalArea > 0) {
            percent = (int) (wipeArea * 100 / totalArea);
        }
        return percent;
    }
}

  

posted @ 2016-02-06 13:14  chenyizh  阅读(142)  评论(0)    收藏  举报