失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > Android 自定义View实现圆形头像(适用于任意布局)

Android 自定义View实现圆形头像(适用于任意布局)

时间:2023-07-17 20:25:48

相关推荐

Android 自定义View实现圆形头像(适用于任意布局)

先看效果图:

先来说下我的思路:首先我需要在自定义View中动态获取头像id,那么就需要在attrs文件中,写一个关于该View类的自定义属性。这里仿照ImageView,取名为src,类型为reference引用类型

<?xml version="1.0" encoding="utf-8"?><resources><declare-styleable name="CircleImageView"><attr name="src" format="reference"/></declare-styleable></resources>

然后在xml布局文件中,使用CircleImageView控件并加上这个“src”属性,表示我要通过src来获取图片引用

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"><com.hualinfo.myviewtext.MyCircleImageViewandroid:id="@+id/head"android:layout_width="100dp"android:layout_height="100dp"app:src="@mipmap/head"android:layout_marginLeft="15dp"android:layout_marginTop="15dp"/></RelativeLayout>

接着,我们在CircleImageView类里调用该属性来获取图片

//获取自定义属性private void getCustomType(){TypedArray array=context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);headBitmap= BitmapFactory.decodeResource(getResources(),array.getResourceId(R.styleable.CircleImageView_src,0));}

R.styleable.CircleImageView_src:这是特定的书写模式,declare-styleable标签的name属性值_attr标签的name属性值

通过以上步骤,我们就能动态获取到自己在布局页面中设置的图片。下面,我们来分析一下如何将图片变成圆形:

首先,canvas.drawCircle()方法是用来绘制一个圆的,但是传参时不能传入一张图片,也就是bitmap。了解过Shader着色器的应该知道,有一个类叫BitmapShader,它被创建的时候,需要传入一个bitmap,然后这个shader会被作为参数传给Paint画笔。这就是我们需要的,我们可以将上面动态获取到的bitmap作为参数传给Shader,Shader再传给Paint,最后在drawCircle()传入该Paint画笔,这样图片就能以圆形的样式显示出来了。具体代码如下:

public MyCircleImageView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);getCustomType(context,attrs);init();}private void init(){shader=new BitmapShader(headBitmap,Shader.TileMode.CLAMP,Shader.TileMode.CLAMP);matrix=new Matrix();paint=new Paint();paint.setAntiAlias(true);}private void initPaintShader(){ //初始化画笔shaderfloat scaleX=1,scaleY=1;//如果图片与圆的直径不一致,等比例缩放图片if(headBitmap.getWidth()!=radius*2||headBitmap.getHeight()!=radius*2){scaleX=(radius*2)/(headBitmap.getWidth()*1.0f);scaleY=(radius*2)/(headBitmap.getHeight()*1.0f);}matrix.setScale(scaleX,scaleY);shader.setLocalMatrix(matrix);paint.setShader(shader);}

好了,通过以上方法,已经可以成功绘制出圆形头像。那么最后,我们要解决的问题是如何让自定义View可以在布局文件随意使用,我们需要适配控件中的padding属性,以及根据它的宽,高的测量模式,改变我们drawCircle时传入的半径radius参数。

1、重写onMeasure方法,动态调整radius圆形半径

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int modeX=MeasureSpec.getMode(widthMeasureSpec);int modeY=MeasureSpec.getMode(heightMeasureSpec);int sizeX=MeasureSpec.getSize(widthMeasureSpec);int sizeY=MeasureSpec.getSize(heightMeasureSpec);//width和height都是EXACTLY(精确)的测量模式if(modeX == MeasureSpec.EXACTLY && modeY == MeasureSpec.EXACTLY){radius=sizeX<sizeY?sizeX/2:sizeY/2;}else if(modeX == MeasureSpec.EXACTLY){radius=sizeX/2;}else if(modeY == MeasureSpec.EXACTLY){radius=sizeY/2;}//width和height都是AT_MOST(尽可以大)的测量模式,或者是UNSPECIAL(无上限)else{radius=headBitmap.getWidth()<headBitmap.getHeight()?headBitmap.getWidth()/2:headBitmap.getHeight()/2;}initPaintShader();//保存测量宽度和测量高度setMeasuredDimension(radius*2, radius*2);}

2、在onDraw()中适配padding属性:

@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);int realRadius=radius;//根据padding值,获取真实的圆的半径if(getPaddingLeft()+getPaddingRight()>=getPaddingTop()+getPaddingBottom())realRadius=(realRadius*2-getPaddingLeft()-getPaddingRight())/2;elserealRadius=(realRadius*2-getPaddingTop()-getPaddingBottom())/2;//根据padding值,设置圆心的真实坐标canvas.drawCircle(radius+getPaddingLeft()-getPaddingRight(),radius+getPaddingTop()-getPaddingBottom(),realRadius,paint);}

通过以上两步,就能够成功适配了。我们可以在布局文件中随意调整常用属性。

最后呈上完整代码:

import android.content.Context;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.BitmapShader;import android.graphics.Canvas;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.Shader;import android.util.AttributeSet;import android.view.View;import androidx.annotation.Nullable;public class MyCircleImageView extends View {private Bitmap headBitmap; //头像图片private int radius; //圆的半径private Paint paint; //自定义画笔private Matrix matrix;private Shader shader;public MyCircleImageView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);getCustomType(context,attrs);init();}private void init(){shader=new BitmapShader(headBitmap,Shader.TileMode.CLAMP,Shader.TileMode.CLAMP);matrix=new Matrix();paint=new Paint();paint.setAntiAlias(true);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int modeX=MeasureSpec.getMode(widthMeasureSpec);int modeY=MeasureSpec.getMode(heightMeasureSpec);int sizeX=MeasureSpec.getSize(widthMeasureSpec);int sizeY=MeasureSpec.getSize(heightMeasureSpec);//width和height都是EXACTLY(精确)的测量模式if(modeX == MeasureSpec.EXACTLY && modeY == MeasureSpec.EXACTLY){radius=sizeX<sizeY?sizeX/2:sizeY/2;}else if(modeX == MeasureSpec.EXACTLY){radius=sizeX/2;}else if(modeY == MeasureSpec.EXACTLY){radius=sizeY/2;}//width和height都是AT_MOST(尽可以大)的测量模式,或者是UNSPECIAL(无上限)else{radius=headBitmap.getWidth()<headBitmap.getHeight()?headBitmap.getWidth()/2:headBitmap.getHeight()/2;}initPaintShader();//保存测量宽度和测量高度setMeasuredDimension(radius*2, radius*2);}private void initPaintShader(){ //初始化画笔shaderfloat scaleX=1,scaleY=1;//如果图片与圆的直径不一致,等比例缩放图片if(headBitmap.getWidth()!=radius*2||headBitmap.getHeight()!=radius*2){scaleX=(radius*2)/(headBitmap.getWidth()*1.0f);scaleY=(radius*2)/(headBitmap.getHeight()*1.0f);}matrix.setScale(scaleX,scaleY);shader.setLocalMatrix(matrix);paint.setShader(shader);}//获取自定义属性private void getCustomType(Context context,AttributeSet attrs){TypedArray array=context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);headBitmap= BitmapFactory.decodeResource(getResources(),array.getResourceId(R.styleable.CircleImageView_src,0));}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);int realRadius=radius;//根据padding值,获取真实的圆的半径if(getPaddingLeft()+getPaddingRight()>=getPaddingTop()+getPaddingBottom())realRadius=(realRadius*2-getPaddingLeft()-getPaddingRight())/2;elserealRadius=(realRadius*2-getPaddingTop()-getPaddingBottom())/2;//根据padding值,设置圆心的真实坐标canvas.drawCircle(radius+getPaddingLeft()-getPaddingRight(),radius+getPaddingTop()-getPaddingBottom(),realRadius,paint);}}

如果觉得《Android 自定义View实现圆形头像(适用于任意布局)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。