每日一学(二)刮刮卡效果实现

一、原理及分析

       

       1、核心原理:xfermode 

                      xfermode是android绘图过程中用来处理两张图片叠加效果的,关于它的详细介绍请移步:http://blog.csdn.net/iispring/article/details/50472485  这篇博客里详细讲解了xfermode的实现原理、用法及使用过程中的坑。

      ps: 圆角图片、圆形头像也是可以用xfermode实现的,省时省力呐!

         2、实现过程分析

                刮刮卡共分为两层,底层是奖项,这里假定为一张图片,上层是刮奖涂层,我们在屏幕上刮奖的过程,是处理onTouch事件,在底层的奖项图片上实时绘制我们的滑动路径,关键点就在于,在绘制我们的滑动路径之前,设置xfermode,取两张图片的交集部分且显示奖项层。这样就实现了我们在刮奖的时候,一点一点的显示奖项层。同时每一次抬起手指的时候计算 刮奖涂层里空白像素的面积,当达到一定的比例时,只绘制奖项层,这样这实现了奖项层的完全展示。

二、代码实现 

        知道了原理,实现起来就简单啦!这里先放一张效果图

         

        我们自定义的刮刮卡View核心代码如下:

           

package com.bec.scratchcard;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Xfermode;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * 刮刮卡View
 * Created by ZGP on 2017/6/7.
 */

public class ScratchCardView extends View {

    private Bitmap mBitmap, mBackBitmap;
    private Paint mPaint, mBackPint;
    private Path mPath;
    private int mLastX;
    private int mLastY;
    private boolean isComplete;
    private Xfermode mXfermode;
    /**
     * 绘制线条的Paint,即用户手指绘制Path
     */
    private Paint mOutterPaint;
    private Rect mTextBound;
    /**
     * 内存中创建的Canvas
     */
    private Canvas mCanvas;
    private String mText = "一等奖";
    private CountThread mCountThread;

    public ScratchCardView(Context context) {
        super(context);
        init();
    }

    public ScratchCardView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {

        mCountThread = new CountThread();
        mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
        mPaint = new Paint();
        //路径记录滑动屏幕的路径。
        mPath = new Path();


        mTextBound = new Rect();

        mBackBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.wallpaper);

        //设置刮奖区样式
        mBackPint = new Paint();
        mBackPint.setColor(Color.RED);
        mBackPint.setStrokeWidth(40);
        mBackPint.setStyle(Paint.Style.FILL);
        mBackPint.setTextScaleX(5f);
        mBackPint.setColor(Color.RED);
        mBackPint.setTextSize(30);
        mBackPint.getTextBounds(mText, 0, mText.length(), mTextBound);


        // 设置画笔
        mOutterPaint = new Paint();
        mOutterPaint.setColor(Color.RED);
        mOutterPaint.setAntiAlias(true);
        mOutterPaint.setDither(true);
        mOutterPaint.setStyle(Paint.Style.STROKE);
        mOutterPaint.setStrokeJoin(Paint.Join.ROUND); // 圆角
        mOutterPaint.setStrokeCap(Paint.Cap.ROUND); // 圆角
        // 设置画笔宽度
        mOutterPaint.setStrokeWidth(20);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 初始化bitmap
        if (mBitmap == null) {
            int width = getMeasuredWidth();
            int height = getMeasuredHeight();
            mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            mCanvas = new Canvas(mBitmap);
            mCanvas.drawColor(Color.parseColor("#c0c0c0"));
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制奖项信息,这里用一个文本实现,也可以绘制一张图片
        canvas.drawText(mText, getWidth() / 2 - mTextBound.width() / 2,
                getHeight() / 2 + mTextBound.height() / 2, mBackPint);
        if (!isComplete) {
            //如果刮奖涂层已被刮掉部分没有达到预设的比例,设置xfermode为DST_OUT,绘制用户刮的路径
            mOutterPaint.setXfermode(mXfermode);
            mCanvas.drawPath(mPath, mOutterPaint);
            canvas.drawBitmap(mBitmap, 0, 0, null);
        }

    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mCountThread != null && mCountThread.isAlive()) {
            isComplete = true;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (action) {

            case MotionEvent.ACTION_DOWN:
                mLastX = x;
                mLastY = y;
                mPath.moveTo(mLastX, mLastY);
                break;
            case MotionEvent.ACTION_MOVE:
                int dx = Math.abs(x - mLastX);
                int dy = Math.abs(y - mLastY);
                if (dx > 3 || dy > 3) {
                    mPath.lineTo(x, y);
                }
                mLastX = x;
                mLastY = y;
                break;
            case MotionEvent.ACTION_UP:
                if (!mCountThread.isAlive()&&!isComplete) {
                    mCountThread.start();
                }
                break;
        }
        invalidate();
        return true;
    }

    /**
     * 计算刮奖涂层已被刮掉部分的比例
     */
    class CountThread extends Thread {
        private int[] mPixels;

        @Override
        public void run() {
            while (!isComplete) {
                int w = getWidth();
                int h = getHeight();

                float wipeArea = 0;
                float totalArea = w * h;

                Bitmap bitmap = mBitmap;

                mPixels = new int[w * h];

                /**
                 * 拿到所有的像素信息
                 */
                bitmap.getPixels(mPixels, 0, w, 0, 0, w, h);

                /**
                 * 遍历统计擦除的区域
                 */
                for (int i = 0; i < w; i++) {
                    for (int j = 0; j < h; j++) {
                        int index = i + j * w;
                        if (mPixels[index] == 0) {
                            wipeArea++;
                        }
                    }
                }

                /**
                 * 根据所占百分比,进行一些操作
                 */
                if (wipeArea > 0 && totalArea > 0) {
                    int percent = (int) (wipeArea * 100 / totalArea);
                    if (percent > 70) {
                        isComplete = true;
                        postInvalidate();
                    }
                }
            }
        }
    }

}
    

    源码下载地址:http://download.csdn.net/detail/u010838555/9866853

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值