自定义View 实现 刮刮卡效果和美女撕衣服

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhuwentao16/article/details/50897280

直奔高潮,不对,直奔主题。

效果图:
这里写图片描述

下面上代码:

public class TearView extends View {

    private Paint paint,paintB;
    private Canvas canva;
    private Bitmap bf;
    private Path path;
    private int width, height;

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

    private void init() {
        //设置画笔的基本参数
        path = new Path();
        paint = new Paint();
        paint.setAntiAlias(true);
        //橡皮擦效果 必须设置透明度为0 才有效
        paint.setAlpha(0);
        paint.setXfermode(new   PorterDuffXfermode(PorterDuff.Mode.DST_IN));

        paint.setStrokeWidth(10);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeJoin(Paint.Join.ROUND);

    //简单的设置下 中奖文字画笔
        paintB = new Paint();
        paintB.setColor(Color.RED);
        paintB.setAntiAlias(true);
        paintB.setTextSize(26);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = MeasureSpec.getSize(widthMeasureSpec);
        height = MeasureSpec.getSize(heightMeasureSpec);
        //这里在布局设置了参数,只是为了显示效果,所以偷懒,不调用setMeasuredDimension()方法了
        bf = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
        canva = new Canvas(bf);
        canva.drawColor(Color.GRAY);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //记录滑动的路线
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                path.moveTo(event.getX(), event.getY());
                break;
            case MotionEvent.ACTION_MOVE:
                path.lineTo(event.getX(), event.getY());
                break;
        }
        canva.drawPath(path, paint);
        invalidate();
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawText("一等奖",width/3,height/2,paintB);
        canvas.drawBitmap(bf, 0, 0, null);
    }

PorterDuffXfermode 控制的是两个图像的混合模式。一共有16中模式,而达到刮刮卡的效果,用到的就是其中的一种:PorterDuff.Mode.DST_IN,具体效果可以参考官网的API示例图。
这里写图片描述
dst是先画的图形,src是后画的图形。平时用的最多的就是,用一张图片作为另一张图片的遮罩层,然后通过控制遮罩层,来控制下面的图形的显示效果,对于上面的例子,灰色的图层,就是遮罩层,在上面使用”橡皮擦”,整天效果就变成刮刮卡了。

画图功能的橡皮擦,也可以用到上面的混合模式。

public class PaintView extends View{

    public Paint paint;
    private Canvas canva;
    private Path path;
    private Bitmap bitmap;

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

    private void init(Context context){
        paint = new Paint();
        paint.setStrokeWidth(30);
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeJoin(Paint.Join.ROUND);
        path = new Path();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        bitmap = Bitmap.createBitmap(MeasureSpec.getSize(widthMeasureSpec),MeasureSpec.getSize(heightMeasureSpec), Bitmap.Config.ARGB_8888);
        canva = new Canvas(bitmap);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                path.moveTo(event.getX(),event.getY());
                break;
            case MotionEvent.ACTION_MOVE:
                path.lineTo(event.getX(), event.getY());
                break;
            case MotionEvent.ACTION_UP:
                path.reset();
                break;
        }
        canva.drawPath(path,paint);
        invalidate();
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.WHITE);
        canvas.drawBitmap(bitmap,0,0,null);
    }

使用橡皮擦功能时,修改paint即可。
效果图:
这里写图片描述

 paint.setStyle(Paint.Style.STROKE);
                paint.setAlpha(0);
                paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
                paint.setStrokeJoin(Paint.Join.ROUND);
                paint.setStrokeWidth(30);
                paintView.setPaint(paint);

这让我想起了以前玩的 “美女撕衣服” 游戏,咳咳,不对,是研究。其实也是两张图片用这张模式混合,然后”撕”掉她们的衣服。
哈哈,先上效果图:
这里写图片描述

这次不用View,而是换成SurfaceView,因为View是通过刷新重新绘制,刷新的间隔事件是16ms,也就是1000/16,一秒60桢,也就是说在16ms内,View中要完成所有操作,这样人的视觉上就不会产生卡顿,如果要处理的操作太多,那么就会不断阻塞主线程,导致画面卡顿。在游戏里尤其明显,一般的FPS游戏,60桢和30桢区别就比较明显。所以,当你的自定义View需要频繁刷新,或者刷新时,数据处理量比较大时,推荐用SurfaceView,两者区别主要有三方面:

  1. View 适用于主动更新,SurfaceView适用于被动更新
  2. View在主线程中对画面进行刷新,SurfaceView通常通过一个子线程来进行页面的刷新。
  3. View 在绘图时没有使用双缓冲机制,SurfaceView在底层机制中就已经实现了双缓冲机制。
public class EraserView extends SurfaceView {

    private Paint paint;
    private Path path;
    private Bitmap bg,fg;
    private Canvas canva,canvas;
    private SurfaceHolder holder;

    public EraserView(Context context, AttributeSet attrs) {
        super(context, attrs);
        holder = getHolder();
        paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setAlpha(0);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeWidth(50);
        path = new Path();
        bg = BitmapFactory.decodeResource(getResources(), R.drawable.bf);
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg);
        fg = Bitmap.createBitmap(bg.getWidth(),bg.getHeight(), Bitmap.Config.ARGB_8888);
        canva = new Canvas(fg);
        canva.drawBitmap(bitmap,0,0,null);

    }



    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                path.reset();
                path.moveTo(event.getX(),event.getY());
                break;
            case MotionEvent.ACTION_MOVE:
                path.lineTo(event.getX(),event.getY());
                break;
        }
        draw();
        return true;
    }

    private void draw(){
        try {
            canvas = holder.lockCanvas();
            canvas.drawBitmap(bg,0,0,null);
            canva.drawPath(path, paint);
            canvas.drawBitmap(fg,0,0,null);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (null != canvas){
                holder.unlockCanvasAndPost(canvas);
            }
        }
    }
}

使用时,注意在绘制方法中,finally要加入unlockCanvasAndPost(canvas),来保证每次都能将内容提交。

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页