圆形头像之BitmapShader,Matrix实现篇

来源:互联网 发布:动态规划的最优化原理 编辑:程序博客网 时间:2024/04/29 22:10

利用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;// 绘制图像的Paintprivate 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();}@Overrideprotected 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;}@Overrideprotected 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"/>



如果试的时候出现什么问题,烦请说一下哈,一起进步。

0 0