自定义View学习之12/2

上一篇我们自定义学习画了一个圆形等级条,并附带延时线程完成动画。
今天我们来弄个比较好玩的,(刮刮乐)。
首先先想好策略。
1、肯定是需要一张背景图。
2、再是需要一张覆盖在背景图上面的灰色不透明图块。
3、当我们手指在灰色图块移动一次均会将路径绘制到灰色不透明图块上,但是因为绘制路径是透明的,计算生成的混合图像也会是透明的。所以我们会得到“橡皮擦”的效果。

好了。策略已想好,下面开始贴代码。

private Bitmap fgBitmap, frontBitmap;// 前景橡皮擦的Bitmap和背景我们底图的Bitmap

    private Canvas mCanvas;// 绘制橡皮擦路径的画布

    private Paint mPaint;// 橡皮檫路径画笔

    private Path mPath;// 橡皮擦绘制路径

    private float x, y;

    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

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

    public CustomView(Context context) {
        super(context);
    }

    private void init() {
        // 实例化路径对象
        mPath = new Path();

        // 实例化画笔并开启其抗锯齿和抗抖动
        mPaint = new Paint();
        // 防锯齿
        mPaint.setAntiAlias(true);
        // 防抖动
        mPaint.setDither(true);
        // 设置混合模式为DST_IN
        mPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
        // 设置画笔风格为描边
        mPaint.setStyle(Paint.Style.STROKE);
        // 设置路径结合处样式
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        // 设置笔触类型
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        // 设置描边宽度
        mPaint.setStrokeWidth(50);

        // 生成前景图Bitmap 这里拿的宽高要在onDraw里面才能拿到哦。
        fgBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_4444);
        // 拿到灰色背景图
        frontBitmap = CreateBitmap(Color.GRAY, getWidth(), getHeight());

        // 将其注入画布
        mCanvas = new Canvas(fgBitmap);
        // 绘制灰色背景图
        mCanvas.drawBitmap(frontBitmap, 0, 0, null);
    }
    /** 获取传入颜色,高端,宽度的Bitmap*/
    public Bitmap CreateBitmap(int color, int width, int height) {
        int[] rgb = new int[width * height];

        for (int i = 0; i < rgb.length; i++) {
            rgb[i] = color;
        }

        return Bitmap.createBitmap(rgb, width, height, Config.ARGB_8888);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mCanvas == null) {
            init();
        }
        // 绘制前景
        canvas.drawBitmap(fgBitmap, 0, 0, null);
        /*
         * 这里要注意canvas和mCanvas是两个不同的画布对象
         * 当我们在屏幕上移动手指绘制路径时会把路径通过mCanvas绘制到fgBitmap上
         * 每当我们手指移动一次均会将路径mPath作为目标图像绘制到mCanvas上,而在上面我们先在mCanvas上绘制了中性灰色
         * 两者会因为DST_IN模式的计算只显示中性灰,但是因为mPath的透明,计算生成的混合图像也会是透明的
         * 所以我们会得到“橡皮擦”的效果
         */
        mCanvas.drawPath(mPath, mPaint);
        super.onDraw(canvas);
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        /*
         * 获取当前事件位置座标
         */
        x = event.getX();
        y = event.getY();

        if (event.getAction() == MotionEvent.ACTION_DOWN) {// 手指接触屏幕重置路径
            mPath.reset();
            mPath.moveTo(x, y);
            // 重绘视图
            invalidate();
            return true;
        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {// 手指移动时连接路径
            mPath.lineTo(x, y);
            // 重绘视图
            invalidate();
            return true;
        }
        return super.onTouchEvent(event);
    }

xml布局如下:
ImageView要跟自定义放一起哦,不然刮出来就没内容了。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView
        android:layout_width="400dp"
        android:layout_height="400dp"  
        android:layout_centerInParent="true"
        android:src="@drawable/bb" />

    <com.customguaguale.CustomView
        android:id="@+id/CustomView_b"
        android:layout_width="400dp"
        android:layout_height="400dp"
        android:layout_centerInParent="true" />

</RelativeLayout>

效果图如下:

这是涂刮层。嘿嘿赶紧动手刮刮吧,看看能刮出什么来。。。

我刮我刮我刮刮刮刮刮……………………..

这里写图片描述

刮出了个美女…..好白好嫩……..是我女朋友多好。。。。。

咳。。。。。。。好吧,我承认我想多了。。

欢迎大家指正错误,以及更优化方案。
下面是源码地址:(http://download.csdn.net/detail/u013895206/8437885

未完待续。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章