您的位置:首页 > 移动开发 > 微信开发

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);

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息