网上的都是自己绘制的或者图片,我的需求是可以随意的自定义底部和顶部的布局。所以自己重写一个,原理就是直接继承 View 来实现一个刮层,让这个刮层和图片以及文字不产生任何依赖,再结合 FrameLayout 将刮层放置最上一层,刮层之下你想放多少图片文字,图片文字要怎么布局摆放都行。由于是FrameLayout ,刮层的上面想加内容都是可以的。如图:

原理:刮刮卡无非就是文本,或者图片,就是我们下边的布局,然后在其上绘制刮奖层,设置DST_OUT,然后把用户触摸绘制上去;这样消失以后就能看到背后的奖了。

布局

 <FrameLayout
        android:layout_width="350dp"
        android:layout_centerInParent="true"
        android:layout_height="150dp">
        <include
            layout="@layout/scratch_view_after"/>
        <coordemo.ly.com.myapplication.GuaGuaKaView
            android:layout_width="match_parent"
            android:id="@+id/gg1"
            android:layout_height="match_parent" />
    </FrameLayout>

  

刮一刮控件
public class GuaGuaKaView extends View {
    /**
     * 绘制线条的画笔
     */
    private Paint mOutterPaint = new Paint();
    /**
     * 遮层画笔
     */
    private Paint mMaskPaint = new Paint();
    /**
     * 最下面画笔
     */
    private Paint mBackPint = new Paint();
    /**
     * mCanvas绘制内容在其上
     */
    private Bitmap mBitmap;
    /**
     * 记录用户绘制的Path
     */
    private Path mPath = new Path();
    /**
     * 内存中创建的Canvas
     */
    private Canvas mCanvas;
    private boolean isComplete;
    private Rect mTextBound = new Rect();
    private String mText = "¥500,0000";
    private int mLastX;
    private int mLastY;
    private int measuredWidth;
    private int measuredHeight;
    public GuaGuaKaView(Context context) {
        this(context, null);
    }
    public GuaGuaKaView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public GuaGuaKaView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }
    private void init() {
        mPath = new Path();
        setUpOutPaint();
        setUpBackPaint();
    }
    /**
     * 初始化canvas的绘制用的画笔
     */
    private void setUpBackPaint() {
        mBackPint.setStyle(Style.FILL);
        mBackPint.setTextScaleX(2f);
        mBackPint.setColor(Color.DKGRAY);
        mBackPint.setTextSize(32);
        mBackPint.getTextBounds(mText, 0, mText.length(), mTextBound);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        if (!isComplete) {
            drawPath();
            canvas.drawBitmap(mBitmap, 0, 0, null);
        } else {
            this.setVisibility(GONE);
        }
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        measuredWidth = getMeasuredWidth();//宽高和父view的相同
        measuredHeight = getMeasuredHeight();
        // 初始化bitmap
        mBitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
        mMaskPaint.setColor(Color.parseColor("#00000000"));//遮层透明
        mMaskPaint.setStyle(Style.FILL);
        mCanvas.drawRoundRect(new RectF(0, 0, measuredWidth, measuredHeight), 0, 0, mMaskPaint);
        mCanvas.drawBitmap(BitmapFactory.decodeResource(getResources(),
                R.drawable.award_1), null, new RectF(0, 0, measuredWidth, measuredHeight), null);//遮层
    }
    /**
     * 设置画笔的一些参数
     */
    private void setUpOutPaint() {
        // 设置画笔
//         mOutterPaint.setAlpha(0);
        mOutterPaint.setColor(Color.parseColor("#c0c0c0"));
        mOutterPaint.setAntiAlias(true);
        mOutterPaint.setDither(true);
        mOutterPaint.setStyle(Style.STROKE);
        mOutterPaint.setStrokeJoin(Paint.Join.ROUND); // 圆角
        mOutterPaint.setStrokeCap(Paint.Cap.ROUND); // 圆角
        // 设置画笔宽度
        mOutterPaint.setStrokeWidth(50);
    }
    /**
     * 绘制线条
     */
    private void drawPath() {
        mOutterPaint.setStyle(Style.STROKE);
        mOutterPaint
                .setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));//取俩者的交集
        mCanvas.drawPath(mPath, mOutterPaint);
    }
    @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;
                new Thread(mRunnable).start();
                break;
            case MotionEvent.ACTION_UP:
                new Thread(mRunnable).start();
                break;
        }
        invalidate();
        return true;
    }
    /**
     * 统计擦除区域任务
     */
    private Runnable mRunnable = new Runnable() {
        private int[] mPixels;
        @Override
        public void run() {
            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);
//                Log.e("TAG", percent + "");
                if (percent > 50) {
//                    Log.e("TAG", "清除区域达到50%,下面自动清除");
                    isComplete = true;
                    postInvalidate();
                }
            }
        }
    };
    /**
     * 将布局转换成bitmap
     * @param addViewContent
     * @return
     */
    private Bitmap getViewBitmap(View addViewContent) {
        addViewContent.setDrawingCacheEnabled(true);
        addViewContent.measure(
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
        addViewContent.layout(0, 0,
                addViewContent.getMeasuredWidth(),
                addViewContent.getMeasuredHeight());
        addViewContent.buildDrawingCache();
        Bitmap cacheBitmap = addViewContent.getDrawingCache();
        Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
        return bitmap;
    }
}

  

 

GitHub地址:

 
 
 
 
 
 

Android刮刮卡自定义控件的更多相关文章

  1. Android 自定义控件实现刮刮卡效果 真的就只是刮刮卡么

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40162163 , 本文出自:[张鸿洋的博客] 很久以前也过一个html5的刮刮卡 ...

  2. Android 自定义View修炼-【2014年最后的分享啦】Android实现自定义刮刮卡效果View

    一.简介: 今天是2014年最后一天啦,首先在这里,我祝福大家在新的2015年都一个个的新健康,新收入,新顺利,新如意!!! 上一偏,我介绍了用Xfermode实现自定义圆角和椭圆图片view的博文& ...

  3. Android 自己定义控件实现刮刮卡效果 真的就仅仅是刮刮卡么

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40162163 , 本文出自:[张鸿洋的博客] 非常久以前也过一个html5的刮刮 ...

  4. 【Android - 自定义View】之自定义View实现“刮刮卡”效果

    首先来介绍一下这个自定义View: (1)这个自定义View的名字叫做 GuaguakaView ,继承自View类: (2)这个View实现了很多电商项目中的“刮刮卡”的效果,即用户可以刮开覆盖层, ...

  5. Android项目刮刮奖详解扩展篇——开源刮刮奖View的制作

    Android项目刮刮奖详解(四) 前言 我们已经成功实现了刮刮奖的功能了,本期是扩展篇,我们把这个View直接定义成开源控件,发布到JitPack上,以后有需要也可以直接使用,关于自定义控件的知识, ...

  6. 用c#开发微信 (16) 微活动 2 刮刮卡

    微信营销是一种新型的营销模式,由于微信更重视用户之间的互动,故而这种营销推广不不能盲目地套用微博营销的单纯大量广告推送方式.这种方式在微信营销中的效果非常差,会令用户反感,继而取消去企业或商家的微信公 ...

  7. Android项目刮刮奖详解(三)

    Android项目刮刮奖详解(二) 前言 上一期我们已经实现了一个简易的刮刮卡功能,这一期我们来将其完善一下 目标 将刮刮奖的宽高改为合适高度 将刮刮奖位置居中 将信息层的图片换成文字(重点) 实现 ...

  8. Android项目刮刮奖详解(四)

    Android项目刮刮奖详解(三) 前言 上一期我们已经是完成了刮刮卡的基本功能,本期就是给我们的项目增加个功能以及美化一番 目标 增加功能 用户刮卡刮到一定程度的时候,清除遮盖层 在遮盖层放张图片, ...

  9. Android打造完美的刮刮乐效果控件

    技术:Android+Java   概述 趁着元旦假期之际,首先在这里,我祝福大家在新的2019年都一个个的新健康,新收入,新顺利,新如意!!! 上一偏,我介绍了用Xfermode实现自定义圆角和椭圆 ...

随机推荐

  1. dubbo2.5.6从下载到编译成功并且部署成功过程

    本文基于dubbo2.5.6版本 原文链接:http://www.cnblogs.com/zhuwenjoyce/       1,下载dubbo 首先从 github 下载源代码并阅读 readme ...

  2. TCP/IP的那些事--子网掩码

    当前互联网使用的主要是IPv4协议,它是第一个被广泛使用,构成现今互联网的基础的协议.但是,随着用户数量的增多,IPv4包含的IP资源在不断减少.或许你会想,不是还有IPv6吗?IPv6的容量足以应付 ...

  3. 【十八】php文件下载源码

    index.php <!DOCTYPE html> <html> <head> <title></title> <meta chars ...

  4. Python 项目实践二(生成数据)第二篇之随机漫步

    接着上节继续学习,在本节中,我们将使用Python来生成随机漫步数据,再使用matplotlib以引人瞩目的方式将这些数据呈现出来.随机漫步是这样行走得到的路径:每次行走都完全是随机的,没有明确的方向 ...

  5. 【1】ArcGIS API for JavaScript 4.5/4.6 本地部署

    惭愧,和我的学弟比起来,我所开始接触前端开发,ArcGIS API for JavaScript的时间和深度远远不及于他. 一年之尾,亦是一年之始,我也将正式开始我的博客生涯.本人在校学习并且做项目, ...

  6. boost::format(字符串格式化库)

    这段时间学习boost库的使用,撰文一方面留以备用,另一方面就是shared精神. format主要是用来格式化std::string字符串以及配合std::cout代替C语言printf() 使用f ...

  7. 2018第一发:记一次【Advanced Installer】打包之旅

    一.前言 2017年最后几天,你们都高高兴兴的跨年,博主还在加班制作.net安装包.因为年前要出来第一版的安装包,所以博主是加班加点啊.本来想用VS自带的制作工具,不过用过的人都知道,真是非常好(to ...

  8. bzoj 3571: [Hnoi2014]画框

    Description 小T准备在家里摆放几幅画,为此他买来了N幅画和N个画框.为了体现他的品味,小T希望能合理地搭配画与画框,使得其显得既不过于平庸也不太违和.对于第 幅画与第 个画框的配对,小T都 ...

  9. 【二十七】php之绘图技术(gd、jpgraph、短信随机验证码)

    1.绘图技术(GD库) 注意:使用该库,php.ini文件中的extension=php_gd2.dll必须是开启状态,不然无法使用 图片格式:目前网站开发常见的图片格式有gif,jpg/jpeg,p ...

  10. Sublime Text 3 配置分析与我的配置---小结

    Sublime Text 3 配置解释(默认){// 设置主题文件"color_scheme": "Packages/Color Scheme – Default/Mon ...