博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
仿制支付宝刮刮卡
阅读量:7168 次
发布时间:2019-06-29

本文共 6722 字,大约阅读时间需要 22 分钟。

跟支付宝那个刮刮卡差不多,体验可能更好点(个人以为)

先看图:

这是刮开的效果图

看起来还可以吧 当刮开面积超过70%的时候,显示全部底图

使用

xml

复制代码

activity

ScratchCardView scratchCardView = findViewById(R.id.scratch_card_01);        scratchCardView.setDownLayer(R.drawable.down);//设置谜底        scratchCardView.setUpLayer(R.drawable.up);//设置遮盖层      //这是刮开谜底完成的回调        scratchCardView.setOnCompleteListener(new ScratchCardView.OnCompleteListener() {            @Override            public void onComplete() {                Log.d(TAG,"完成00");           }        });复制代码

setDownLayer和setUpLayer还支持文字、颜色和Bitmap

---------------------只使用看到这里就可以了----------------------------------

刮卡需要实现的基本代码

Bitmap canvasBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);//创建一个Bitmp        Canvas scratchCanvas = new Canvas(canvasBitmap);//初始化画布        RectF rectF = new RectF(0, 0, width, height);//初始化画布和遮盖层绘制的位置        scratchCanvas.drawBitmap(upLayer.bitmap, null, rectF, null);//把还在遮盖绘制到画布上        Paint pathPaint = new Paint();        pathPaint.setColor(Color.WHITE);//颜色随意,只要不是透明                pathPaint.setStrokeWidth(50);        pathPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));//这里是重点        scratchCanvas.drawPath(path, pathPaint);//把path绘制到画布上,这条遮盖层会被消除        //然后在onDraw或者dispatchDraw使用view的Canvas绘制这个canvasBitmap 就可以了复制代码

Coding

绘制

@Override    protected void dispatchDraw(Canvas canvas) {        super.dispatchDraw(canvas);        if (rectF != null) {            //绘制下面的图层            drawDownLayer(canvas);            //绘制上面的图层            if (!isComplete) {                canvas.drawBitmap(canvasBitmap, null, rectF, null);            }        }    }复制代码

直接在dispatchDraw方法中绘制即可,不过我这里为了方便多种类型的绘制,做了一下封装,根据文字,颜色和图片分类绘制

绘制下面的图层比较简单

private void drawDownLayer(Canvas canvas) {        if (downLayer != null) {            switch (downLayer.type) {                case TYPE_BITMAP:                    canvas.drawBitmap(downLayer.bitmap, null, rectF, null);                    break;                case TYPE_COLOR:                    canvas.drawColor(downLayer.color);                    break;                case TYPE_TEXT:                    canvas.drawColor(downLayer.color);                    canvas.drawText(downLayer.text, downLayer.textStartX, downLayer.textStartY, downLayer.paint);                    break;            }        }    }复制代码

绘制上面的图层

绘制上面的额图层就比较麻烦了,先创建一个跟View相同大小的Bitmap,使用它作为Canvas操作的对象,先把上面的图(遮盖层)绘制到上面,

private void initCanvas(int width, int height) {        //初始化画布        canvasBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);        scratchCanvas = new Canvas(canvasBitmap);        rectF = new RectF(0, 0, width, height);        if (downLayer.type == TYPE_TEXT) {            measureDownText();        }        drawUpLayer();    }复制代码

初始化一个Path记录手机移动的位置,初始化Path的Paint

        pathPaint = new Paint();         pathPaint.setColor(Color.WHITE);//颜色随意,只要不是透明         pathPaint.setAntiAlias(true);         pathPaint.setDither(true);         pathPaint.setStyle(Paint.Style.STROKE);         pathPaint.setStrokeJoin(Paint.Join.ROUND); // 圆角         pathPaint.setStrokeCap(Paint.Cap.ROUND); // 圆角         pathPaint.setStrokeWidth(50);         pathPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));//这里是重点         //初始化path         path = new Path(); 复制代码

关于Xfermode,这里配上经典说明图一张

也就是path的Paint的Xfermode类型是DST_OUT的情况,path所绘制的区域都会变成透明

重写onTouchEvent,记录使用path记录手指轨迹,并绘制在我们创建的画布上(scratchCanvas )

@Override    public boolean onTouchEvent(MotionEvent event) {        int x = (int) (event.getX());        int y = (int) (event.getY());        int offsetX = (int) (rectF != null ? rectF.left : 0);        int offsetY = (int) (rectF != null ? rectF.top : 0);        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                mLastX = x;                mLastY = y;                path.moveTo(x - offsetX, y - offsetY);                getParent().requestDisallowInterceptTouchEvent(true);                break;            case MotionEvent.ACTION_MOVE:                int dx = Math.abs(x - mLastX);                int dy = Math.abs(y - mLastY);                if (dx > 3 || dy > 3) {                    //贝塞尔曲线                    path.quadTo(mLastX - offsetX, mLastY - offsetY, (x + mLastX) / 2 - offsetX, (y + mLastY) / 2 - offsetY);                }                mLastX = x;                mLastY = y;                break;            case MotionEvent.ACTION_UP:                getParent().requestDisallowInterceptTouchEvent(false);                computeScratchArea();                break;            case MotionEvent.ACTION_CANCEL:                getParent().requestDisallowInterceptTouchEvent(false);                computeScratchArea();                break;        }        drawPath();        invalidate();        return true;    } private void drawPath() {        if (scratchCanvas != null) {            scratchCanvas.drawPath(path, pathPaint);        }  }复制代码

计算刮开的面积

即就死按画布上透明像素所占比例,这里思路源于洋神,洋神无敌

private void computeScratchArea() {        if (!isComplete) {            executorService.execute(runnable);        } else {            executorService.shutdownNow();        }    }    //在子线程计算    private Runnable runnable = new Runnable() {        @Override        public void run() {            if (isComplete) {                return;            }            Bitmap bitmap = canvasBitmap;            int w = getWidth();            int h = getHeight();            int[] pixels = new int[w * h];            float wipeArea = 0;            float totalArea = w * h;            //获取像素数据            bitmap.getPixels(pixels, 0, w, 0, 0, w, h);            //遍历色素值为0的像素,也就是透明区域            for (int i = 0; i < w; i++) {                for (int j = 0; j < h; j++) {                    int index = i + j * w;                    if (pixels[index] == 0) {                        wipeArea++;                    }                }            }            if (wipeArea > 0 && totalArea > 0) {                int percent = (int) (wipeArea * 100 / totalArea);                Log.e("TAG", percent + "");                if (percent > 70 && !isComplete) {                    isComplete = true;                    postInvalidate();                    Log.d(TAG, "........." + isComplete);                    if (onCompleteListener != null) {                        post(new Runnable() {                            @Override                            public void run() {                                onCompleteListener.onComplete();                            }                        });                    }                }            }        }    };复制代码

描述能力有限,看不懂的小伙伴,直接看代码:

-----------------------------------------------------------------------------------------------------------

暴富镇楼

转载地址:http://xjqwm.baihongyu.com/

你可能感兴趣的文章
centos 快速部署L2TP服务
查看>>
sed 批量修改Makefile文件
查看>>
有关netapp中vol status命令的convert_ucode=on选项的解释
查看>>
利用阿里云SDK获取OSS存储值的办法
查看>>
opencv 图片位移
查看>>
voip rsvp配置示例
查看>>
VC++使用CImage在内存中Bmp转换Jpeg图片
查看>>
科目分类与借贷方的关系
查看>>
统计经典SQL(构建日期补0)
查看>>
技术团队代码管理和部署
查看>>
TI_DSP链接命令文件(*.cmd)的介绍
查看>>
lsof 命令
查看>>
andriod底层最简开发流程
查看>>
最大子序列积
查看>>
我的译作《精通OpenStack》上架啦:书籍介绍和译者序
查看>>
Linux V4L2之camera
查看>>
详细剖析Linux防火墙配置
查看>>
seq用法总结
查看>>
Python正则表达式指南
查看>>
gitlab安装(基于centos6.5)
查看>>