欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

自定义View时,用到Paint Canvas的一些温故,讲讲平时一些效果是怎么画的(基础篇 二,图像遮盖,Canvas静态变化)

来源: 开发者 投稿于  被查看 28358 次 评论:50

自定义View时,用到Paint Canvas的一些温故,讲讲平时一些效果是怎么画的(基础篇 二,图像遮盖,Canvas静态变化)


上一篇把简单的一些概念理一理,还画了个圈,那这一篇讲一下图像遮盖“Xfermode”和Canvas的旋转。平移等效果

Xfermode:

AvoidXfermode 指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图)。

PixelXorXfermode 当覆盖已有的颜色时,应用一个简单的像素异或操作。

PorterDuffXfermode 这是一个非常强大的转换模式,使用它,可以使用图像合成的16条Porter-Duff规则的任意一条来控制Paint如何与已有的Canvas图像进行交互。

我们今天的呈现就是在PorterDuffXfermode 这部分实现的

PorterDuff.Mode为枚举类,一共有16个枚举值分别是

1.PorterDuff.Mode.CLEAR
所绘制不会提交到画布上。
2.PorterDuff.Mode.SRC
显示上层绘制图片
3.PorterDuff.Mode.DST
显示下层绘制图片
4.PorterDuff.Mode.SRC_OVER
正常绘制显示,上下层绘制叠盖。
5.PorterDuff.Mode.DST_OVER
上下层都显示。下层居上显示。
6.PorterDuff.Mode.SRC_IN
取两层绘制交集。显示上层。
7.PorterDuff.Mode.DST_IN
取两层绘制交集。显示下层。
8.PorterDuff.Mode.SRC_OUT
取上层绘制非交集部分。
9.PorterDuff.Mode.DST_OUT
取下层绘制非交集部分。
10.PorterDuff.Mode.SRC_ATOP
取下层非交集部分与上层交集部分
11.PorterDuff.Mode.DST_ATOP
取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR
异或:去除两图层交集部分
13.PorterDuff.Mode.DARKEN
取两图层全部区域,交集部分颜色加深
14.PorterDuff.Mode.LIGHTEN
取两图层全部,点亮交集部分颜色
15.PorterDuff.Mode.MULTIPLY
取两图层交集部分叠加后颜色
16.PorterDuff.Mode.SCREEN
取两图层全部区域,交集部分变为透明色

在将这一系列的效果之前我们先把我们昨天画圆的例子改一下

public class TestView extends View {
    Paint paint;
    Context context;
    Bitmap bitmap;

    public TestView(Context context) {
        super(context);
        this.context = context;
    }

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

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

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public TestView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        paint = new Paint();
//        paint.setColor(getResources().getColor(R.color.SlateBlue));
        paint.setColor(getResources().getColor(R.color.Gold));
        paint.setStrokeWidth(3);                        //粗细
        paint.setAntiAlias(true);                       //设置画笔为无锯齿
        bitmap= BitmapFactory.decodeResource(getResources(),R.drawable.bg);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.d("--->onDraw", "onDraw()");
//        canvas.drawCircle(0, 0, 90, paint);
        canvas.drawBitmap(bitmap,0,0,paint);
        canvas.drawCircle(100, 100, 90, paint);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        Log.d("--->onLayout", "changed = " + changed + " left = " + left + " top = " + top + " right = " + right + " bottom " + bottom);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        Log.d("--->onMeasure", "  widthMeasureSpec =" + widthMeasureSpec + "  heightMeasureSpec = " + heightMeasureSpec);
        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
    }
}

我们在画圆之后又画了个背景图,效果如下:

这里写图片描述

在我们的圆下面有一个妹子,并且圆是会盖掉妹子那一块圆的涂抹面积的。

那我们把onDraw()方法里执行的顺序换一下呢?

   @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.d("--->onDraw", "onDraw()");
//        canvas.drawCircle(0, 0, 90, paint);
          canvas.drawCircle(100, 100, 90, paint);
          canvas.drawBitmap(bitmap,0,0,paint);   
    }

如果改成这样,我们的圆就没了(效果不贴了)

利用PorterDuff.Mode就可以很好的解决这个问题当然,可能你得多绘制一次然后再做覆盖的操作了,所以在你决定先画什么后画什么之前一定理清谁在前谁在后

本来想写个大致的例子,但是想想16个都好麻烦,就拿了一个市面上比较多的图吧

这里写图片描述


Canvas静态变化

上面的代码不变,我们在新建一个Canvas然后把他里面话一点东西,来模拟我们想要的效果。

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.d("--->onDraw", "onDraw()");
//        canvas.drawCircle(0, 0, 90, paint);
        canvas.drawCircle(100, 100, 90, paint1);
        canvas.drawBitmap(bitmap, 120, 120, paint1);
        Canvas canvas1=new Canvas(bitmap);

        Paint paint2=new Paint();
        paint2.setColor(getResources().getColor(R.color.LightPink));
        paint2.setTextSize(50);
        canvas1.drawText("Ezreal", 0, 200, paint2);

        canvas1.drawText("Malzahar ",0,300,paint2);
    }

效果如下:

这里写图片描述

P1.我们用画布又画了2个字。那么我们来试下各种效果(分析和方法,会分两部分罗列)

平移:1.void translate(float dx, float dy)<喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPsa90sayzsr9o7oyuPbX+LHqteNY1f3P8tPSIFnV/c/yz8KjrLi6yv23tNauoaM8L3A+DQo8cD48c3Ryb25nPtD916o8L3N0cm9uZz6jujxiciAvPg0KMS52b2lkIHJvdGF0ZShmbG9hdCBkZWdyZWVzKTxiciAvPg0KMi52b2lkIHJvdGF0ZSAoZmxvYXQgZGVncmVlcywgZmxvYXQgcHgsIGZsb2F0IHB5KTwvcD4NCjxwPtD916qyzsr9o7rS1Nf4serUrbXjo6jX88nPo6nOqtD916rW0NDE16pkZWdyZWVztsijqNX9tcTOqtX916qjrLi6tcTOqre016qjqaOscHgscHnOqtLUKHB4LHB5Kc6q1tDQxND916pkZWdyZWVztsguPC9wPg0KPHA+PHN0cm9uZz7L9bfFPC9zdHJvbmc+o7o8YnIgLz4NCjEucHVibGljIHZvaWQgc2NhbGUgKGZsb2F0IHN4LCBmbG9hdCBzeSk8YnIgLz4NCjIucHVibGljIGZpbmFsIHZvaWQgc2NhbGUgKGZsb2F0IHN4LCBmbG9hdCBzeSwgZmxvYXQgcHgsIGZsb2F0IHB5KTwvcD4NCjxwPsv1t8Wyzsr9o7pzeM6qy67Gvcv1t8WjrDGx7cq+srux46OstPPT2jG3xbTzo6zQodPrMcv10KGjqLi6tcTO0sO7ytS5/aOpo7tzedTyse3KvrS51rGjrMLfvK3NrMuuxr0uPC9wPg0KPHA+PHN0cm9uZz7QscfQPC9zdHJvbmc+o7o8L3A+DQo8cD4xLnZvaWQgc2tldyAoZmxvYXQgc3gsIGZsb2F0IHN5KTwvcD4NCjxwPtCxx9Cyzsr9o7pzeDq9q7utsrzU2ni3vc/yyc/H49Cxz+DTprXEvce2yKOsc3jH49Cxvce2yLXEdGFu1rWju3N5Or2ru62yvNTaedbht73P8snPx+PQsc/g06a1xL3HtsijrHN5zqrH49Cxvce2yLXEdGFu1rUuPC9wPg0KPGhyIC8+DQo8cD5QMi7Ktc/W0tS8sL3iys2jujwvcD4NCjxwPjEuxr3SxqO6PGJyIC8+DQo8aW1nIGFsdD0="这里写图片描述" src="http://www.2cto.com/uploadfile/Collfiles/20151230/20151230092039134.png" title=""http://zz.2cto.com/seo/" target="_blank" class="keylink">seorMzAwo6xZ1/ix6iszMDCjqaGjPC9wPg0KPHA+tavKxyDQp7n7ysfV4tH5wvCjvzwvcD4NCjxwPs6qwcvR6dakyLfKtcjntMvO0sPH1NnU2dPSsuC7rdK7uPYmbGRxdW87QWthbGkmcmRxdW87PC9wPg0KPHByZSBjbGFzcz0="brush:java;"> //并且是在平移前执行 canvas1.drawText("Akali ",200,400,paint2);

这里写图片描述

然后我们在平移之后再画一个Katarina Du Couteau

并且跟平移前的阿卡丽是用以坐标

  canvas1.drawText("Katarina Du Couteau ", 200, 400, paint2);

这里写图片描述

效果是卡特跟着整个坐标系走了而不是之前的坐标相加的结果。

所以:

1.每次调用canvas.drawXXXX系列函数来绘图进,都会产生一个全新的Canvas画布。
2.在Canvas与屏幕合成时,超出屏幕范围的图像是不会显示出来的。

2.旋转

我们还是回到最初的蚂蚱和EZ的样子

  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.d("--->onDraw", "onDraw()");
//        canvas.drawCircle(0, 0, 90, paint);
        canvas.drawCircle(100, 100, 90, paint1);
        canvas.drawBitmap(bitmap, 120, 120, paint1);
        Canvas canvas1 = new Canvas(bitmap);

        Paint paint2 = new Paint();
        paint2.setColor(getResources().getColor(R.color.LightPink));
        paint2.setTextSize(50);
//        canvas1.drawText("Akali ", 200, 400, paint2);

//        canvas1.translate(300, 300);
        canvas1.drawText("Ezreal", 0, 200, paint2);
        canvas1.rotate(30);
        canvas1.drawText("Malzahar ", 0, 300, paint2);

//        canvas1.drawText("Katarina Du Couteau ", 200, 400, paint2);
    }

然后把蚂蚱旋转30度,效果如图

这里写图片描述

EZ位置没变,蚂蚱转了,并且有一部分超出了我们的妹子Bitmap所以它不见了。

然后此时此刻,我们的阿卡丽回来了,并且在蚂蚱之后

这里写图片描述

我们的啊卡里也跟着蚂蚱转走了,说明旋转和平移是一样的整个位图转走了。

如下图向着箭头方向偏了30度然后创建了一个新的Canvas

这里写图片描述

3.缩放

缩放的图我就不画了,代码就是canvas.scale(1, 1.5f); 就是Y方向缩放1.5f

也是重绘了一个Canvas和上面都一样。

4.斜切
其实也就是可以实现我们的一个斜体的效果,这里就贴一下执行效果

这里写图片描述

还有就是int save () void restore()相对比较简单,对堆栈的概念清晰的小伙伴一看就懂,不需要过多试验,这里就不明说了。

用户评论