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

来源:互联网 发布:sqlserver触发器实例 编辑:程序博客网 时间:2024/05/17 01:47

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

效果图:
这里写图片描述

下面上代码:

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),来保证每次都能将内容提交。

0 0