在日常开发中,我们经常需要用到圆形图片,最近总结了3个绘制圆形图片的方法,在这里总结一下
BitmapShader
是 Shader
的子类,Shader
是 画笔的着色器,是用于给画布着色,利用 BitmapShader
,我们可以给画布绘制一个圆形图片:
public class CircleHeadView extends View {
private Paint mPaint;
....
{
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
//Shader.TileMode.CLAMP为拉伸图片铺满
BitmapShader bitmapShader = new BitmapShader(getBitmap(dp2px(100))
, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(bitmapShader);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制一个圆形,圆形的颜色就是我们指定的图片
canvas.drawCircle(dp2px(50), dp2px(50), dp2px(50), mPaint);
}
private Bitmap getBitmap(int width) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.drawable.bg_header, options);
options.inJustDecodeBounds = false;
//设置位图的屏幕密度,即每英寸有多少个像素
options.inDensity = options.outWidth;
//设置位图被画出来时的目标像素密度
//与options.inDensity配合使用,可对图片进行缩放
options.inTargetDensity = width;
return BitmapFactory.decodeResource(getResources(), R.drawable.bg_header, options);
}
/**
* 将dp或dp值转换为px值,保证尺寸大小不变
*/
private int dp2px(float dpValue) {
float scale = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue
, Resources.getSystem().getDisplayMetrics());
return (int) (scale + 0.5f);
}
}
可以看到运行结果:
一个漂亮的圆形图片就出来了
使用图像混合模式,我们也可以很简单弄出一个圆形图片:
public class CircleHeadView extends View {
private Paint mPaint;
....
{
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
// BitmapShader mBitmapShader = new BitmapShader(getBitmap(dp2px(100))
// , Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
// mPaint.setShader(mBitmapShader);
//设置图像混合模式
mPorterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
//开启软件加速
setLayerType(View.LAYER_TYPE_SOFTWARE, mPaint);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//设置离线缓存层,图像混合计算都需要在上面计算,从而生成新的图像
int save = canvas.saveLayer(dp2px(50), dp2px(50)
, dp2px(150), dp2px(150), mPaint, Canvas.ALL_SAVE_FLAG);
canvas.drawCircle(dp2px(100), dp2px(100)
, dp2px(50), mPaint);
mPaint.setXfermode(mPorterDuffXfermode);
canvas.drawBitmap(getBitmap(dp2px(100)), dp2px(50), dp2px(50), mPaint);
mPaint.setXfermode(null);
//恢复画布,将图像绘制到上面
canvas.restoreToCount(save);
}
private Bitmap getBitmap(int width) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.drawable.bg_header, options);
options.inJustDecodeBounds = false;
//设置位图的屏幕密度,即每英寸有多少个像素
options.inDensity = options.outWidth;
//设置位图被画出来时的目标像素密度
//与options.inDensity配合使用,可对图片进行缩放
options.inTargetDensity = width;
return BitmapFactory.decodeResource(getResources(), R.drawable.bg_header, options);
}
/**
* 将dp或dp值转换为px值,保证尺寸大小不变
*/
private int dp2px(float dpValue) {
float scale = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue
, Resources.getSystem().getDisplayMetrics());
return (int) (scale + 0.5f);
}
}
可以看到运行结果:
关于图片混合模式,建议看 Hencoder 这文章,里面说的很详细了,这里就不多说了
我们还可以使用裁剪画布的方法来弄出一个圆形的图片,在执行了 clipPath
方法后,绘制都会限制在裁剪的范围里面:
public class CircleHeadView extends View {
private Paint mPaint;
private Path mClipPath;//用于固定裁剪的范围
private RectF mRectF;//用于固定图片的绘制范围
..........
{
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mClipPath = new Path();
mClipPath.addCircle(dp2px(150), dp2px(150), dp2px(50)
, Path.Direction.CW);
mRectF = new RectF();
mRectF.set(dp2px(100), dp2px(100), dp2px(200), dp2px(200));
//开启软件加速
setLayerType(View.LAYER_TYPE_SOFTWARE, mPaint);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//这里需要开启离屏缓存层,裁剪过程应该放在离屏缓存层,避免对原画布产生影响
int saveCount = canvas.saveLayer(dp2px(100), dp2px(100)
, dp2px(200), dp2px(200), mPaint, Canvas.ALL_SAVE_FLAG);
//裁剪画布
canvas.clipPath(mClipPath);
//在指定范围内绘制图片
canvas.drawBitmap(getBitmap(dp2px(100)), null, mRectF, mPaint);
//将离屏缓存的绘制复制到画布上面
canvas.restoreToCount(saveCount);
}
private Bitmap getBitmap(int width) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.drawable.bg_header, options);
options.inJustDecodeBounds = false;
//设置位图的屏幕密度,即每英寸有多少个像素
options.inDensity = options.outWidth;
//设置位图被画出来时的目标像素密度
//与options.inDensity配合使用,可对图片进行缩放
options.inTargetDensity = width;
return BitmapFactory.decodeResource(getResources(), R.drawable.bg_header, options);
}
/**
* 将dp或dp值转换为px值,保证尺寸大小不变
*/
private int dp2px(float dpValue) {
float scale = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue
, Resources.getSystem().getDisplayMetrics());
return (int) (scale + 0.5f);
}
}
可以看到运行效果: