自定义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)

平移参数:2个坐标点X正向右 Y正向下,负数反之。

旋转
1.void rotate(float degrees)
2.void rotate (float degrees, float px, float py)

旋转参数:以坐标原点(左上)为旋转中心转degrees度(正的为正转,负的为反转),px,py为以(px,py)为中心旋转degrees度.

缩放
1.public void scale (float sx, float sy)
2.public final void scale (float sx, float sy, float px, float py)

缩放参数:sx为水平缩放,1表示不便,大于1放大,小与1缩小(负的我没试过);sy则表示垂直,逻辑同水平.

斜切

1.void skew (float sx, float sy)

斜切参数:sx:将画布在x方向上倾斜相应的角度,sx倾斜角度的tan值;sy:将画布在y轴方向上倾斜相应的角度,sy为倾斜角度的tan值.


P2.实现以及解释:

1.平移:
这里写图片描述

肉眼看来我们的2个字偏移了canvas1.translate(300,300);的位置,效果类似于 2个字体本身的坐标(X坐标+300,Y坐标+300)。

但是 效果是这样吗?

为了验证确实如此我们再再右侧画一个“Akali”

//并且是在平移前执行
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()相对比较简单,对堆栈的概念清晰的小伙伴一看就懂,不需要过多试验,这里就不明说了。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值