Canvas实战

来源:互联网 发布:杭州市软件行业协会 编辑:程序博客网 时间:2024/06/08 18:39

一、圆角矩形图片实现

这里写图片描述

图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