Android 画笔特效处理——刮刮卡效果

不管是在我们的世界里,还是在Android的世界里,要想向神笔马良一样画出各种经常决绝的画,就必须有一个前提——要有一支神奇的画笔。我们应该对一些常用的画笔属性有所了解,比如普通的画笔(Paint),带边框、填充的style,颜色(Color),宽度(StrokeWidth),抗锯齿(ANTI_ALIAS_FLAG)等,这些都是最近的画笔属性,就好像一个普通人说拥有的画笔工具。然而除此之外,还有各种各样的专业画笔工具,如记号笔、毛笔、蜡笔等,使用它们可以实现更加丰富的绘图效果。下面我们就来看看画笔的一些高级属性,帮助我么实现更丰富的绘图效果。

● PorterDuffXfermode

在学习这个东西以前,先来看一张非常经典的图,出自API Demo,基本上所有讲PorterDuffXfermode的文章都会使用这张图说明,如图(1)所示。

 

                                                                                                (1)

图(1)中距离了16种PorterDuffXfermode,有点像数学几何的交集、并集这样的概念,相信大家配合图例应该很好理解,它控制的是两个图像间的混合显示模式。

这里要注意的是,PorterDuffXfermode设置的是两个图层交集区域的显示方式,dst是先画的图形,而src是后画的图形。

当然,这些模式也不是经常使用的,用的最多是,使用一张图片作为另一张图片的遮罩层,通过控制遮罩层的图形,来控制下面遮罩层图形的显示效果。其中最常用的就是通过DST_IN、SRC_IN模式来实现将一个矩形图片变成圆角图片或者圆形图片的效果。

要使用PorterDuffXfermode非常简单,只需要让画面有这个属性就可以了,比如下面要实现如图(2)所示实例。

                                                                                               (2)

先用一个普通画笔话一个Mask遮罩层,再用带PorterDuffXfermode的画笔将图像画在遮罩层上,这样就可以通过上面所说的效果来混合两个图像了,代码如下所示。

        mBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.asdf);
        mOut = Bitmap.createBitmap(mBitmap.getWidth(),mBitmap.getHeight(),Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(mOut);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        canvas.drawRoundRect(0,0,mBitmap.getWidth(),mBitmap.getHeight(),20,20,mPaint);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(mBitmap,0,0,mPaint);

下面再来做一个稍微复杂的效果——刮刮卡效果。我们都知道,刮刮卡一般有两个图层,即上面的用来被挂掉的图层和下面隐藏的图层。在初始状态下,上面的图层会将下面的图层覆盖,当你用手刮上面的图层时候,下面的图层会慢慢显示出来,这也类似很多画图工具中的橡皮擦效果。这个效果同样可以使用PortDuffXfermode来实实现。

首先需要做一些初始化工作,例如准备好图片、设置好Paint的一些属性,代码如下所示。

        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeWidth(50);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPath = new Path();
        mBgBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.asdf);
        mFgBitmap = Bitmap.createBitmap(mBgBitmap.getWidth(),mBgBitmap.getHeight(),Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mFgBitmap);
        mCanvas.drawColor(Color.GRAY);

在上面的代码中,给Paint设置一些属性,让它的笔触和连接更加圆滑一点,即Paint.Join.ROUND和Paint.Cap.ROUND属性。

接下来,看一下如何获取用户手指滑动所产生的路径,代码如下所示。使用Path保存用户手指划过的路径。当然,这里如果使用贝赛尔曲线来做优化则会得到更好的显示效果,这里为了简化演示功能,就不使用贝塞尔曲线了。

        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                mPath.reset();
                mPath.moveTo(event.getX(),event.getY());
                break;
            case MotionEvent.ACTION_MOVE:
                mPath.lineTo(event.getX(),event.getY());
                break;
        }

最后,只需要使用DST_IN模式将路径绘制到前面覆盖的图层上面即可。不过,还行做最关键的一步,那就是将画笔的透明度设置为0,这样才能显示擦除效果。很多读者可能不太理解这里将透明度设置为0的原因,这里因为在使用PorterDuffXfermode进行图层混合时,并不是简单地只进行图层的计算,同时也会去计算透明度的通道值。正是由于混合了透明通道,才形成了这样的效果,完整代码如下所示。

public class XfermodeView extends View {
    private Bitmap mBgBitmap,mFgBitmap;
    private Paint mPaint;
    private Canvas mCanvas;
    private Path mPath;

    public XfermodeView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setAlpha(0);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeWidth(50);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPath = new Path();
        mBgBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.asdf);
        mFgBitmap = Bitmap.createBitmap(mBgBitmap.getWidth(),mBgBitmap.getHeight(),Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mFgBitmap);
        mCanvas.drawColor(Color.GRAY);
    }

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(mBgBitmap.getWidth(),
                mBgBitmap.getHeight());

    }


    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(mBgBitmap,0,0,null);
        canvas.drawBitmap(mFgBitmap,0,0,null);
    }
}

程序运行效果如图(3)所示,当用户手指滑动时,就会擦除上面的涂层,形成刮刮卡效果。

                                                                                                 (3)

在使用PorterDuffXfermode是还有一点需要注意,那就是最好在绘图时,将硬件加速关闭,因为有些模式并不支持硬件加速。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页