Canvas实战

一、圆角矩形图片实现

这里写图片描述

图1


实现方案与网上其它实现方式略有不同,本方案处理圆角效果针对的不是图片本身,而是显示区域,代码如下:

@Override
    protected void onDraw(Canvas canvas) {

        //通过setImageResource()
        Drawable drawable = getDrawable();
        //setBackgroundResource
        if (null == drawable)
         drawable =getBackground();
        if (null != drawable) {

            //清空之前画布的内容
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            canvas.drawPaint(mPaint);


            Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
            final Rect rectSrc = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
            final Rect rectDes = new Rect(0,0,getWidth(),getHeight());
            final RectF rectF = new RectF(rectDes);
            float radius= getResources().getDimension(R.dimen.radius_activity);

            mPaint.reset();

            //绘制圆角区域,颜色随意设置即可
            mPaint.setColor(Color.GREEN);
            canvas.drawRoundRect(rectF, radius, radius, mPaint);


            //取上下两层的交集
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

            //将图像真正绘制到View区域
            canvas.drawBitmap(bitmap, rectSrc, rectDes, mPaint);


            //至此整个圆角区域的绘制成功,但是有黑边,如下图2


            //将黑边渲染成背景
            mPaint.setColor(getResources().getColor(R.color.color_common_bg));
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
            canvas.drawPaint(mPaint);

            mPaint.setXfermode(null);

        } else {
            super.onDraw(canvas);

        }
    }

至于为什么会有黑色区域,黑边,答案也是显然的,因为这一块区域在两个图层取交集的时候没有绘制。
这里写图片描述

图2

二、仅有上半圆角矩形图片实现

这里写图片描述

图3

在用xml定义各种shape时,可以分别定义矩形各个角的圆角半径大小,其对应的Drawable实现类为GradientDrawable,查看源代码可知,其主要绘制Path路径实现,实现代码如下:

protected void onDraw(Canvas canvas) {


        //setImageResource()
        Drawable drawable = getDrawable();
        //setBackgroundResource
        if (null == drawable)
         drawable =getBackground();
        if (null != drawable) {

            //清空之前画布的内容
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            canvas.drawPaint(mPaint);


            Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
            final Rect rectSrc = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
            final Rect rectDes = new Rect(0,0,getWidth(),getHeight());
            final RectF rectF = new RectF(rectDes);
            float radius= getResources().getDimension(R.dimen.radius_activity);

            mPaint.reset();

            //绘制上半部分圆角区域,颜色随意设置即可
            mPaint.setColor(Color.GREEN);
            mPath.reset();
            mPath.addRoundRect(rectF, new float[]{radius, radius, radius, radius, 0, 0, 0, 0}, Path.Direction.CW);

            canvas.drawPath(mPath, mPaint);


            //取上下两层的交集
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

            //将图像真正绘制到View区域
            canvas.drawBitmap(bitmap, rectSrc, rectDes, mPaint);


            //将黑边渲染成背景
            mPaint.setColor(getResources().getColor(R.color.color_common_bg));
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
            canvas.drawPaint(mPaint);

            mPaint.setXfermode(null);

        } else {
            super.onDraw(canvas);

        }
    }

三、仿微信聊天图片样式实现

这里写图片描述

图4

其主要实现办法,是在圆角形状区域加一个三角形区域,代码如下:
protected void onDraw(Canvas canvas) {


        //setImageResource()
        Drawable drawable = getDrawable();
        //setBackgroundResource()
        if (null == drawable)
         drawable =getBackground();
        if (null != drawable) {

            //清空之前画布的内容
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            canvas.drawPaint(mPaint);


            Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
            final Rect rectSrc = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
            final Rect rectDes = new Rect(0,0,getWidth(),getHeight());

            final Rect rectImage = new Rect(FINAL_X,0,getWidth(),getHeight());
            final RectF rectF = new RectF(rectImage);
            float radius= getResources().getDimension(R.dimen.radius_activity);

            mPaint.reset();



            //绘制三角形和圆角矩形组合的区域,FINAL_X:圆角矩形显示区域向X移动的距离;可通过修改DISTANCE来调整三角区域的宽度
            mPaint.setColor(Color.GREEN);
            mPath.reset();
            mPath.moveTo(FINAL_X, FINAL_Y - DISTANCE);
            mPath.quadTo(FINAL_X, FINAL_Y - DISTANCE, 0, FINAL_Y);
            mPath.quadTo(0, FINAL_Y, FINAL_X, DISTANCE + FINAL_Y);
            mPath.close();

            mPath.addRoundRect(rectF, new float[]{radius, radius, radius, radius, 0, 0, 0, 0}, Path.Direction.CW);

            canvas.drawPath(mPath, mPaint);


            //取上下两层的交集
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));




            //将图像真正绘制到View区域
            canvas.drawBitmap(bitmap, rectSrc, rectDes, mPaint);


            mPaint.setColor(getResources().getColor(R.color.color_common_bg));
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
            canvas.drawPaint(mPaint);

            mPaint.setXfermode(null);

        } else {
            super.onDraw(canvas);

        }
    }

四、仿微信聊天图片样式优化

这里写图片描述

图5

在上面的仿微信聊天图片样式中,本打算用贝塞尔曲线实现圆滑的效果,但定义坐标点完全是直线点,其形成的三角区域有点太直角了,不太美观,所以这次想通过圆角矩形的一部分作为三角头来达到圆滑效果,区域形状如下:
这里写图片描述
图6

其实现的主要代码如下:

 protected void onDraw(Canvas canvas) {


        //通过setImageResource()
        Drawable drawable = getDrawable();
        //setBackgroundResource
        if (null == drawable)
         drawable =getBackground();
        if (null != drawable) {

            //清空之前画布的内容
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            canvas.drawPaint(mPaint);


            Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
            final Rect rectSrc = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
            final Rect rectDes = new Rect(0,0,getWidth(),getHeight());

            final Rect rectImage = new Rect(FINAL_X,0,getWidth(),getHeight());
            final RectF rectF = new RectF(rectImage);
            float radius= getResources().getDimension(R.dimen.radius_activity);

            mPaint.reset();


            //将原始图形绘制到新区域,下图层a
            mPaint.setColor(Color.GREEN);
            canvas.drawBitmap(bitmap, rectSrc, rectDes, mPaint);


            //取上下两层的交集
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));




            //形状区域上图层b
            int sc = canvas.saveLayer(0,0,getWidth(),getHeight(), mPaint, Canvas.CLIP_SAVE_FLAG);

            Paint paint=new Paint();

            //绿色大的圆角矩形
            paint.setColor(Color.GREEN);
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
            mPath.addRoundRect(rectF, new float[]{radius, radius, radius, radius, 0, 0, 0, 0}, Path.Direction.CW);
            canvas.drawPath(mPath, paint);


            mPath.reset();


            //灰色圆角矩形
            paint.setColor(Color.GRAY);
            canvas.save();
            canvas.translate(0, FINAL_Y);
            canvas.rotate(45);
            final RectF tempF = new RectF(0f,-(float)(Math.sqrt(2)*FINAL_X),(float)(Math.sqrt(2)*FINAL_X),0f);
            mPath.addRoundRect(tempF, 6, 6, Path.Direction.CW);
            canvas.drawPath(mPath, paint);
            canvas.restore();




            // 图层a和b合并,形成新效果
            canvas.restoreToCount(sc);



            //将黑边渲染成背景
            mPaint.setColor(getResources().getColor(R.color.color_common_bg));
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
            canvas.drawPaint(mPaint);

            mPaint.setXfermode(null);

        } else {
            super.onDraw(canvas);

        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值