圆形头像之BitmapShader,Matrix实现篇
2016-10-25 22:30
211 查看
利用BitmapShader实现圆形头像的功能,可以定义边框的颜色、大小,支持padding
效果图:(为了方便看一些padding我加了黄色的背景,在onDraw()方法中第一行,去掉就可以了)
![](http://img.blog.csdn.net/20161025222039116?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
代码上该注释的地方已经注释的很清楚了
来贴一下代码:
package com.shj.view.image;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.ImageView;
import com.shj.test.R;
public class RoundImageView extends ImageView {
private int borderColor;// 圆形头像的边框颜色
private int borderWidth;// 圆形头像的边框宽度
private Paint mBitmapPaint;// 绘制图像的Paint
private Paint mBorderPaint;
private Matrix mMatrix;// 图像矩阵,本身是一个3*3矩阵
private int mRadius;
private int mImgWidth;
public RoundImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundImageView(Context context) {
this(context, null);
}
public RoundImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(context, attrs);
mBitmapPaint = new Paint();
mBorderPaint = new Paint();
mMatrix = new Matrix();
mBitmapPaint.setAntiAlias(true);
mBorderPaint.setAntiAlias(true);
}
private void initAttrs(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView);
borderColor = a.getColor(R.styleable.RoundImageView_border_color, Color.parseColor("#ffffff"));
borderWidth = a.getDimensionPixelSize(R.styleable.RoundImageView_border_width,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0,
getResources().getDisplayMetrics()));
a.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//写好一个控件自定义View,写出一个能用的自定义View不易啊。。。
// 虽然测量这块儿寥寥几行代码,但是还得心细啊。。
int imgHeight = setMeasureHeight(heightMeasureSpec)-getPaddingTop() - getPaddingBottom()-borderWidth*2;
int imgWidth = setMeasureWidth(widthMeasureSpec) - getPaddingLeft() - getPaddingRight()-borderWidth*2;
if(imgHeight<imgWidth){
mImgWidth = imgHeight;
mRadius = mImgWidth/2;
}else{
mImgWidth = imgWidth;
mRadius = mImgWidth/2;
}
setMeasuredDimension(setMeasureWidth(widthMeasureSpec),setMeasureHeight(heightMeasureSpec));
}
private int setMeasureHeight(int heightMeasureSpec) {
int height = 0;
int minHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 56,
getResources().getDisplayMetrics());
int specMode = MeasureSpec.getMode(heightMeasureSpec);
int specSize = MeasureSpec.getSize(heightMeasureSpec);
switch (specMode) {
case MeasureSpec.EXACTLY:
height = (specSize < minHeight ? minHeight : specSize);// 此处我是设置了EXACTLY的值,仅是圆形图片大小的值
break;
case MeasureSpec.AT_MOST:
height = minHeight + getPaddingTop() + getPaddingBottom();
break;
case MeasureSpec.UNSPECIFIED:
height = minHeight + getPaddingTop() + getPaddingBottom();
break;
}
return height;
}
private int setMeasureWidth(int widthMeasureSpec) {
int width = 0;
int minWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 56,
getResources().getDisplayMetrics());
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
switch (specMode) {
case MeasureSpec.EXACTLY:
width = (specSize < minWidth ? minWidth : specSize);
break;
case MeasureSpec.AT_MOST:
width = minWidth + getPaddingLeft() + getPaddingRight();
break;
case MeasureSpec.UNSPECIFIED:
width = minWidth + getPaddingRight() + getPaddingLeft();
break;
}
return width;
}
@Override
protected void onDraw(Canvas canvas) {
this.setBackgroundColor(Color.YELLOW);
if (getDrawable() == null) {
return;
}
setShader();
canvas.drawCircle(mRadius + borderWidth + getPaddingLeft(), mRadius + borderWidth + getPaddingTop(),
mRadius, mBitmapPaint);
mBorderPaint.setColor(borderColor);
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setStrokeWidth(borderWidth / 2);
canvas.drawCircle(mRadius + borderWidth + getPaddingLeft(), mRadius + borderWidth + getPaddingTop(),
mRadius + borderWidth / 2, mBorderPaint);
}
/**
* 初始化bitmapShader
*/
private void setShader() {
Drawable drawable = getDrawable();
Bitmap bmp = drawableToBitmap(drawable);
BitmapShader mBitmapShader = new BitmapShader(bmp, TileMode.CLAMP, TileMode.CLAMP);
float scale = 1.0f;
// 去取bitmap中宽度和高度中更小的,为了使图像缩放之后,可以填充满控件的空间,
// 此处切记要乘以1.0f,,这种低级错误写的时候又犯了一次。
scale = mImgWidth * 1.0f / (Math.min(bmp.getWidth(), bmp.getHeight()));
mMatrix.setScale(scale, scale);
mMatrix.postTranslate(getPaddingLeft()+borderWidth, getPaddingTop()+borderWidth);//这里使用了Matrix的后乘进行效果叠加,
// 使图像根据padding进行位移
mBitmapShader.setLocalMatrix(mMatrix);
mBitmapPaint.setShader(mBitmapShader);
}
/**
* 将Drawable转变为bitmap
*/
private Bitmap drawableToBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bd = (BitmapDrawable) drawable;
return bd.getBitmap();
}
int h = drawable.getIntrinsicHeight();
int w = drawable.getIntrinsicWidth();
Bitmap bitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);// 建立对应的bitmap画布
drawable.setBounds(0, 0, w, h);// 此处的setBounds是指,drawable将在canvas的0,0,w,h矩形区域内
drawable.draw(canvas);// 将drawable的内容画到画布中去
return bitmap;
}
}
自定义属性:
布局eg:
如果试的时候出现什么问题,烦请说一下哈,一起进步。
效果图:(为了方便看一些padding我加了黄色的背景,在onDraw()方法中第一行,去掉就可以了)
代码上该注释的地方已经注释的很清楚了
来贴一下代码:
package com.shj.view.image;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.ImageView;
import com.shj.test.R;
public class RoundImageView extends ImageView {
private int borderColor;// 圆形头像的边框颜色
private int borderWidth;// 圆形头像的边框宽度
private Paint mBitmapPaint;// 绘制图像的Paint
private Paint mBorderPaint;
private Matrix mMatrix;// 图像矩阵,本身是一个3*3矩阵
private int mRadius;
private int mImgWidth;
public RoundImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundImageView(Context context) {
this(context, null);
}
public RoundImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(context, attrs);
mBitmapPaint = new Paint();
mBorderPaint = new Paint();
mMatrix = new Matrix();
mBitmapPaint.setAntiAlias(true);
mBorderPaint.setAntiAlias(true);
}
private void initAttrs(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView);
borderColor = a.getColor(R.styleable.RoundImageView_border_color, Color.parseColor("#ffffff"));
borderWidth = a.getDimensionPixelSize(R.styleable.RoundImageView_border_width,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0,
getResources().getDisplayMetrics()));
a.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//写好一个控件自定义View,写出一个能用的自定义View不易啊。。。
// 虽然测量这块儿寥寥几行代码,但是还得心细啊。。
int imgHeight = setMeasureHeight(heightMeasureSpec)-getPaddingTop() - getPaddingBottom()-borderWidth*2;
int imgWidth = setMeasureWidth(widthMeasureSpec) - getPaddingLeft() - getPaddingRight()-borderWidth*2;
if(imgHeight<imgWidth){
mImgWidth = imgHeight;
mRadius = mImgWidth/2;
}else{
mImgWidth = imgWidth;
mRadius = mImgWidth/2;
}
setMeasuredDimension(setMeasureWidth(widthMeasureSpec),setMeasureHeight(heightMeasureSpec));
}
private int setMeasureHeight(int heightMeasureSpec) {
int height = 0;
int minHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 56,
getResources().getDisplayMetrics());
int specMode = MeasureSpec.getMode(heightMeasureSpec);
int specSize = MeasureSpec.getSize(heightMeasureSpec);
switch (specMode) {
case MeasureSpec.EXACTLY:
height = (specSize < minHeight ? minHeight : specSize);// 此处我是设置了EXACTLY的值,仅是圆形图片大小的值
break;
case MeasureSpec.AT_MOST:
height = minHeight + getPaddingTop() + getPaddingBottom();
break;
case MeasureSpec.UNSPECIFIED:
height = minHeight + getPaddingTop() + getPaddingBottom();
break;
}
return height;
}
private int setMeasureWidth(int widthMeasureSpec) {
int width = 0;
int minWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 56,
getResources().getDisplayMetrics());
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
switch (specMode) {
case MeasureSpec.EXACTLY:
width = (specSize < minWidth ? minWidth : specSize);
break;
case MeasureSpec.AT_MOST:
width = minWidth + getPaddingLeft() + getPaddingRight();
break;
case MeasureSpec.UNSPECIFIED:
width = minWidth + getPaddingRight() + getPaddingLeft();
break;
}
return width;
}
@Override
protected void onDraw(Canvas canvas) {
this.setBackgroundColor(Color.YELLOW);
if (getDrawable() == null) {
return;
}
setShader();
canvas.drawCircle(mRadius + borderWidth + getPaddingLeft(), mRadius + borderWidth + getPaddingTop(),
mRadius, mBitmapPaint);
mBorderPaint.setColor(borderColor);
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setStrokeWidth(borderWidth / 2);
canvas.drawCircle(mRadius + borderWidth + getPaddingLeft(), mRadius + borderWidth + getPaddingTop(),
mRadius + borderWidth / 2, mBorderPaint);
}
/**
* 初始化bitmapShader
*/
private void setShader() {
Drawable drawable = getDrawable();
Bitmap bmp = drawableToBitmap(drawable);
BitmapShader mBitmapShader = new BitmapShader(bmp, TileMode.CLAMP, TileMode.CLAMP);
float scale = 1.0f;
// 去取bitmap中宽度和高度中更小的,为了使图像缩放之后,可以填充满控件的空间,
// 此处切记要乘以1.0f,,这种低级错误写的时候又犯了一次。
scale = mImgWidth * 1.0f / (Math.min(bmp.getWidth(), bmp.getHeight()));
mMatrix.setScale(scale, scale);
mMatrix.postTranslate(getPaddingLeft()+borderWidth, getPaddingTop()+borderWidth);//这里使用了Matrix的后乘进行效果叠加,
// 使图像根据padding进行位移
mBitmapShader.setLocalMatrix(mMatrix);
mBitmapPaint.setShader(mBitmapShader);
}
/**
* 将Drawable转变为bitmap
*/
private Bitmap drawableToBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bd = (BitmapDrawable) drawable;
return bd.getBitmap();
}
int h = drawable.getIntrinsicHeight();
int w = drawable.getIntrinsicWidth();
Bitmap bitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);// 建立对应的bitmap画布
drawable.setBounds(0, 0, w, h);// 此处的setBounds是指,drawable将在canvas的0,0,w,h矩形区域内
drawable.draw(canvas);// 将drawable的内容画到画布中去
return bitmap;
}
}
自定义属性:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="RoundImageView"> <attr name="border_width" format="dimension"/> <attr name = "border_color" format="color"/> </declare-styleable> </resources>
布局eg:
<com.shj.view.image.RoundImageView android:id="@+id/img1" android:layout_width="128dp" android:layout_height="128dp" android:src="@mipmap/head" app:border_color="@color/colorAccent" app:border_width="2dp" android:paddingLeft="8dp" android:paddingTop="60dp"/> <com.shj.view.image.RoundImageView android:id="@+id/img2" android:layout_marginTop="8dp" android:layout_below="@+id/img1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/head" android:paddingLeft="16dp" android:paddingTop="8dp"/>
如果试的时候出现什么问题,烦请说一下哈,一起进步。
相关文章推荐
- BitmapShader实现圆形头像
- 精简版BitmapShader实现圆形头像和圆角方形头像
- 使用BitmapShader实现图片的圆形、圆角
- Android BitmapShader 实战 实现圆形、圆角图片
- Android BitmapShader 实战 实现圆形、圆角图片
- Android BitmapShader 实战 实现圆形、圆角图片
- Android 自定义View修炼-Android实现圆形、圆角和椭圆自定义图片View(使用BitmapShader图形渲染方法)
- Android自定义view实现圆形、圆角和椭圆图片(BitmapShader图形渲染)
- Android_BitmapShader实现圆形、圆角图片
- Android BitmapShader实现圆形和圆角图片
- Android使用BitmapShader图形渲染实现圆形、圆角和椭圆自定义图片View
- Android BitmapShader 实战 实现圆形、圆角图片
- 【转】Android BitmapShader 实战 实现圆形、圆角图片
- Android BitmapShader 实战 实现圆形、圆角图片
- Android BitmapShader 实战 实现圆形、圆角图片
- Android BitmapShader 实战 实现圆形、圆角图片
- Android BitmapShader 实战 实现圆形、圆角图片
- Android BitmapShader 实战 实现圆形、圆角图片
- Android BitmapShader实现圆形和圆角图片
- 使用BitmapShader实现圆形,圆角图片