您的位置:首页 > 其它

圆形头像之BitmapShader,Matrix实现篇

2016-10-25 22:30 211 查看
利用BitmapShader实现圆形头像的功能,可以定义边框的颜色、大小,支持padding

效果图:(为了方便看一些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"/>


如果试的时候出现什么问题,烦请说一下哈,一起进步。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: