自定义圆形ImageView
圆形ImageView在头像显示用的比较普遍了,今天对于实现圆形ImageView做个总结;
主要思路是 重写 onDraw() ;方法有两个:
- 使用paint的Shader(着色器)将图片印在一个圆的画板上
- 使用Bitmap创建一个空的Canvas(画板),在画板上画一个圆和显示的图片,paint图像混合模式显示
着色器 方式
不带边框
思路
- 将图片压缩到和控件的大小一致
- 创建Bitmap 着色器
- 创建画笔并设置着色器
- 使用带有着色器的画笔在画板上画圆
private void drawShader(Canvas canvas) {
Drawable mDrawable = getDrawable();
if (mDrawable == null) return;
if (mDrawable instanceof BitmapDrawable){
Bitmap bmp = ((BitmapDrawable)mDrawable).getBitmap();
if (bmp == null) return;
//图片缩放,参数2 目标宽度,参数3目标高度,参数4 是否过滤
bmp = Bitmap.createScaledBitmap(bmp,getWidth(),getHeight(),true);
//着色器
Shader shader = new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint = new Paint();
paint.setShader(shader);
canvas.drawCircle(getWidth()/2,getWidth()/2,getWidth()/2,paint);
}
}
效果
加边框
有时候我们需要为头像加上一个圆的边框显得更好看一点,其实这个也很好实现,在绘制图片之前先绘制一个带有颜色的圆,根据边框的大小,将图片缩小一点,这样就将边框显示出来了。
画边框
代码语言:javascript复制paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(outColor);
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2,paint);
绘制图片 将边框大小空出来 (getWidth()-outWidth*2)/2
代码语言:javascript复制private void drawShader(Canvas canvas) {
Drawable mDrawable = getDrawable();
if (mDrawable == null) return;
if (mDrawable instanceof BitmapDrawable){
Bitmap bmp = ((BitmapDrawable)mDrawable).getBitmap();
if (bmp == null) return;
//图片缩放,参数2 目标宽度,参数3目标高度,参数4 是否过滤
bmp = Bitmap.createScaledBitmap(bmp,getWidth(),getHeight(),true);
//着色器
Shader shader = new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint = new Paint();
paint.setShader(shader);
canvas.drawCircle(getWidth()/2,getWidth()/2,(getWidth()-outWidth*2)/2,paint);
}
}
效果
着色器方式全部代码
自定义属性 边框颜色和宽度
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CircleImageView">
<attr name="out_width" format="dimension"></attr>
<attr name="out_color" format="color"></attr>
</declare-styleable>
</resources>
重写 onDraw() 绘制图片
代码语言:javascript复制package com.skymxc.lesson_36_view_override;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;
/**
* Created by sky-mxc
*/
public class CircleImageView extends ImageView {
private static final String TAG = "CircleImageView";
private int outWidth = 2;
private int outColor = Color.RED;
private Paint paint;
public CircleImageView(Context context) {
this(context,null,0);
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(attrs);
}
@Override
protected void onDraw(Canvas canvas) {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// canvas.drawColor(Color.YELLOW);
paint.setColor(outColor);
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2,paint);
drawShader(canvas);
}
private void drawShader(Canvas canvas) {
Drawable mDrawable = getDrawable();
if (mDrawable == null) return;
if (mDrawable instanceof BitmapDrawable){
Bitmap bmp = ((BitmapDrawable)mDrawable).getBitmap();
if (bmp == null) return;
//图片缩放,参数2 目标宽度,参数3目标高度,参数4 是否过滤
bmp = Bitmap.createScaledBitmap(bmp,getWidth(),getHeight(),true);
//着色器
Shader shader = new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint = new Paint();
paint.setShader(shader);
canvas.drawCircle(getWidth()/2,getWidth()/2,(getWidth()-outWidth*2)/2,paint);
}
}
public void initAttrs(AttributeSet attrs){
TypedArray array = getContext().obtainStyledAttributes(attrs,R.styleable.CircleImageView);
int len = array.length();
for(int i=0;i<len;i ){
int attr = array.getIndex(i);
switch (attr){
case R.styleable.CircleImageView_out_color:
this.outColor = array.getColor(attr,Color.GREEN);
break;
case R.styleable.CircleImageView_out_width:
this.outWidth = (int) array.getDimension(attr,2);
Log.i(TAG, "initAttrs: outWidth=" this.outWidth);
break;
}
}
array.recycle();
}
}
使用图片混合模式显示
代码语言:javascript复制创建 Bitmap 使用图片混合模式 将图片和圆形交叉显示
private Bitmap getCircleBitmap(){
Drawable mDrawable = getDrawable();
if (mDrawable == null) return null;
if (mDrawable instanceof BitmapDrawable){
Bitmap bmp = ((BitmapDrawable)mDrawable).getBitmap();
if (bmp == null) return null;
paint = new Paint();
paint.setAntiAlias(true);
//创建空的位图
Bitmap output = Bitmap.createBitmap(getWidth(),getHeight(), Bitmap.Config.ARGB_8888);
//创建画板,以位图进行创建
Canvas canvas= new Canvas(output);
//Bitmap就成了 透明的图片
canvas.drawColor(Color.TRANSPARENT);
//画一个圆形 和图像大小一致
paint.setColor(Color.WHITE);
canvas.drawCircle(output.getWidth()/2,output.getHeight()/2,output.getWidth()/2,paint);
// //paint 相交模式 必须在 两者中间定义 显示交叉的地方 ;前面是 dst;后面是 src
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//
// //绘制 Bitmap
Rect src = new Rect(0,0,bmp.getWidth(),bmp.getHeight());
RectF dst = new RectF(0,0,output.getWidth(),output.getHeight());
canvas.drawBitmap(bmp,src,dst,paint);
return output;
}
return null;
}
代码语言:javascript复制@Override
protected void onDraw(Canvas canvas) {
Bitmap bmp= getCircleBitmap();
canvas.drawBitmap(bmp,0,0,paint);
}
对于这种方式的实现主要在于 paint 的交叉模式; PorterDuffXfermode
实现的方式有很多种 目前是两种. 未完待续。。。。。