美文网首页自定义控件
Android自定义View实现刮奖效果

Android自定义View实现刮奖效果

作者: itfitness | 来源:发表于2019-02-27 17:31 被阅读13次

    目录

    目录.png

    效果展示

    实现原理

    实现原理通俗的讲就是利用PaintsetXfermode方法设置混合模式,设置的混合模式为PorterDuff.Mode.CLEAR即将手指移动的区域清除,清除后的区域为透明的,所以会将控件下面的刮奖结果显示出来。另外要注意的是在绘制之前需要保存Canvas状态,绘制完成后需要恢复Canvas状态。

    代码展示

    public class ScrapeView extends View {
        private Paint mPaint;
        private Path mPath;
        private PointF mPointF;
        public ScrapeView(Context context) {
            super(context);
            init();
        }
    
        public ScrapeView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        public ScrapeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
        private void init(){
            setLayerType(LAYER_TYPE_SOFTWARE,null);//关闭硬件加速
    
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setStrokeCap(Paint.Cap.ROUND);
            mPaint.setStrokeWidth(20);
    
            mPath = new Path();
    
            mPointF = new PointF();
        }
        /**
         * 修改高度
         * @param widthMeasureSpec
         * @param heightMeasureSpec
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            setMeasuredDimension(measureWidth(widthMeasureSpec),measuredHeight(heightMeasureSpec));
        }
    
        /**
         * 测量宽
         * @param widthMeasureSpec
         */
        private int measureWidth(int widthMeasureSpec) {
            int result ;
            int specMode = MeasureSpec.getMode(widthMeasureSpec);
            int specSize = MeasureSpec.getSize(widthMeasureSpec);
            if (specMode == MeasureSpec.EXACTLY){
                result = specSize;
            }else {
                result = 200;
                if (specMode == MeasureSpec.AT_MOST){
                    result = Math.min(result,specSize);
                }
            }
            return result;
        }
    
        /**
         * 测量高
         * @param heightMeasureSpec
         */
        private int measuredHeight(int heightMeasureSpec) {
            int result ;
            int specMode = MeasureSpec.getMode(heightMeasureSpec);
            int specSize = MeasureSpec.getSize(heightMeasureSpec);
            if (specMode == MeasureSpec.EXACTLY){
                result = specSize;
            }else{
                result = 200;
                if(specMode == MeasureSpec.AT_MOST){
                    result = Math.min(result,specSize);
                }
            }
            return  result;
        }
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            mPath.reset();
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()){
                case MotionEvent.ACTION_DOWN:
                    mPointF.x = event.getX();
                    mPointF.y = event.getY();
                    mPath.moveTo(event.getX(),event.getY());
                    invalidate();
                    return true;
                case MotionEvent.ACTION_MOVE:
                case MotionEvent.ACTION_UP:
                    mPath.quadTo(mPointF.x,mPointF.y,(mPointF.x+event.getX())/2,(mPointF.y+event.getY())/2);//贝赛尔曲线让路径更圆润
                    mPointF.x = event.getX();
                    mPointF.y = event.getY();
                    //下面这行代码依然可以实现效果(只是不够圆润)
    //                mPath.lineTo(event.getX(),event.getY());
                    invalidate();
                    break;
            }
            return super.onTouchEvent(event);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.save();//存储画布状态(离屏绘制)
            mPaint.setColor(Color.GRAY);
            mPaint.setMaskFilter(new BlurMaskFilter(20, BlurMaskFilter.Blur.NORMAL));//给卡片周围加上柔光效果
            mPaint.setStyle(Paint.Style.FILL);
            canvas.drawRect(new RectF(0,0,getWidth(),getHeight()),mPaint);
            mPaint.setMaskFilter(null);//清空MaskFilter,否则刮卡时也是模糊的效果
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));//利用混合模式将手指移动的区域(mPath的路径)清空
            mPaint.setStyle(Paint.Style.STROKE);
            canvas.drawPath(mPath,mPaint);
            mPaint.setXfermode(null);//清除混合模式
            canvas.restore();//恢复上面存储的画布状态
        }
    }
    

    项目源码:https://github.com/myml666/ScrapeDemo

    相关文章

      网友评论

        本文标题:Android自定义View实现刮奖效果

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