圆形头像很常用功能,于是想自己写个自定义的圆形的view。搜索了一下,android中可以通过BitmapShader实现这个效果。
BitmapShader是Shader的子类,可以通过Paint.setShader(Shader shader)进行设置、
这里我们只关注BitmapShader,构造方法:
bitmapShader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP);
参数1:bitmap
参数2,参数3:TileMode;
TileMode的取值有三种:
CLAMP 拉伸
REPEAT 重复
MIRROR 镜像
如果大家给电脑屏幕设置屏保的时候,如果图片太小,可以选择重复、拉伸、镜像;
重复:就是横向、纵向不断重复这个bitmap
镜像:横向不断翻转重复,纵向不断翻转重复;
拉伸:这个和电脑屏保的模式应该有些不同,这个拉伸的是图片最后的那一个像素;横向的最后一个横行像素,不断的重复,纵项的那一列像素,不断的重复;
首先现在values下新建attrs.xml,自定义属性。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CircleImageView">
<attr name="mborder_color" format="color"></attr>
<attr name="mborder_width" format="dimension"></attr>
<attr name="msrc" format="reference"></attr>
</declare-styleable>
</resources>
CircleImageView.java
package com.sy.callme.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import com.sy.callme.R;
/**
* Created by SY on 2016/5/16.
*/
public class CircleImageView extends View {
private Bitmap bitmap;
private int borderWidth;
private Drawable drawable;
private int borderColor;
private int width;
private int height;
private Bitmap src;
private BitmapShader shader;
private Paint paint;
private int radius;
private int circleX;
private int circleY;
private Paint borderPaint;
public CircleImageView(Context context) {
super(context);
}
public CircleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
//获取自定义属性
TypedArray type = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);
borderColor = type.getColor(R.styleable.CircleImageView_mborder_color, 0);
borderWidth = type.getDimensionPixelSize(R.styleable.CircleImageView_mborder_width, 2);
drawable = type.getDrawable(R.styleable.CircleImageView_msrc);
//转换为bitmap
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
bitmap = bitmapDrawable.getBitmap();
}
private int measureHeight(int heightMeasureSpec) {
int size = MeasureSpec.getSize(heightMeasureSpec);
int sizeMode = MeasureSpec.getMode(heightMeasureSpec);
int result = 0;
if (sizeMode == MeasureSpec.EXACTLY) {
//如果是精确尺寸就直接返回结果
result = size;
} else {
//不是就尺寸设置最大为200
result = 200;
if (sizeMode == MeasureSpec.AT_MOST) {
//如果是最大尺寸就返回实际尺寸和最大尺寸之中较小的
result = Math.min(result, size);
}
}
return result;
}
private int measureWidth(int widthMeasureSpec) {
int size = MeasureSpec.getSize(widthMeasureSpec);
int sizeMode = MeasureSpec.getMode(widthMeasureSpec);
int result = 0;
if (sizeMode == MeasureSpec.EXACTLY) {
//如果是精确尺寸就直接返回结果
result = size;
} else {
//如果是精确尺寸就直接返回结果
result = 200;
if (sizeMode == MeasureSpec.AT_MOST) {
//如果是最大尺寸就返回实际尺寸和最大尺寸之中较小的
result = Math.min(result, size);
}
}
return result;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = measureWidth(widthMeasureSpec);
height = measureHeight(heightMeasureSpec);
width = height = Math.min(width, height);
initView();//初始化画笔参数
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(circleX, circleY, radius, paint);
canvas.drawCircle(circleX, circleY, radius, borderPaint);
}
private void initView() {
src = Bitmap.createScaledBitmap(bitmap, width, height, true);
shader = new BitmapShader(src, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint = new Paint();
paint.setShader(shader);//设置shader
radius = (width - borderWidth * 2) / 2;
circleX = (width) / 2;
circleY = (height) / 2;
borderPaint = new Paint();
borderPaint.setStyle(Paint.Style.STROKE);
borderPaint.setStrokeWidth(borderWidth);
borderPaint.setColor(borderColor);
borderPaint.setStrokeJoin(Paint.Join.ROUND);//接合处的圆滑
borderPaint.setStrokeCap(Paint.Cap.ROUND);//圆角的笔触
}
public void setImageResoure(Drawable drawable) {
//转换为bitmap
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
bitmap = bitmapDrawable.getBitmap();
shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint = new Paint();
paint.setShader(shader);
requestLayout();
invalidate();
}
}
首先获取自定义属性的值,然后在onMeasure方法里获得控件宽高,initView方法里设置画笔的参数,创建BitmapShader并给paint设置shader。最后在onDraw方法里绘制就可以了。具体使用:
<com.sy.callme.view.CircleImageView
android:id="@+id/c_image"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginTop="20dp"
android:layout_gravity="center_horizontal"
app:mborder_color="#ff7700"
app:mborder_width="3dp"
app:msrc="@mipmap/touxiang" />
记得使用自定义view的自定义属性需要在布局文件中引入xmlns:app="http://schemas.android.com/apk/res-auto"
参考资料:Android自定义属性时TypedArray的使用方法
Android学习笔记进阶15之Shader渲染
Android学习笔记进阶16之BitmapShader
详解Paint的各种set方法