Canvas实战
2016-09-20 16:07
155 查看
一、圆角矩形图片实现
[align=center]图1[/align]
实现方案与网上其它实现方式略有不同,本方案处理圆角效果针对的不是图片本身,而是显示区域,代码如下:
@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); } }
至于为什么会有黑色区域,黑边,答案也是显然的,因为这一块区域在两个图层取交集的时候没有绘制。
[align=center]图2[/align]
二、仅有上半圆角矩形图片实现
[align=center]图3[/align]
在用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); } }
三、仿微信聊天图片样式实现
[align=center]图4[/align]
其主要实现办法,是在圆角形状区域加一个三角形区域,代码如下:
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); } }
四、仿微信聊天图片样式优化
[align=center]图5[/align]
在上面的仿微信聊天图片样式中,本打算用贝塞尔曲线实现圆滑的效果,但定义坐标点完全是直线点,其形成的三角区域有点太直角了,不太美观,所以这次想通过圆角矩形的一部分作为三角头来达到圆滑效果,区域形状如下:
[align=center]图6[/align]
其实现的主要代码如下:
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); } }
相关文章推荐
- HTML5 Canvas游戏开发实战
- Android绘图Canvas十八般武器之Shader详解及实战篇(上)
- HTML5吃豆豆游戏开发实战(一)使用Canvas绘制游戏主角
- Android实战技巧之二十九:画布Canvas
- HTML5 Canvas实战之刮奖效果
- Canvas实战---模仿GOOGLE浮动小球效果
- HTML5 canvas游戏开发实战 4 : lufylegend开源库件
- 通过Canvas + JS 实现简易时钟实战
- canvas实战之一(画图,矩阵转换,定时)
- canvas实战——圆盘表
- 【全面解禁!真正的Expression Blend实战开发技巧】十一章 全面解析布局(Grid & Canvas &StackPanel &Wrappanel)
- canvas入门实战--邀请卡生成与下载
- HTML5 Canvas实战之刮奖效果
- HTML5 Canvas(画布)实战编程初级篇:基本介绍和基础画布元素
- HTML5 canvas游戏开发实战 6 : 俄罗斯方块
- Android绘图Canvas十八般武器之Shader详解及实战篇(下)
- HTML5 Canvas实战之刮奖效果
- HTML5 Canvas实战之刮奖效果
- HTML5 Canvas(画布)实战编程初级篇:基本介绍和基础画布元素
- HTML5开发之Canvas绘图之实战入门