Android自定义View之圆形图片--RoundImageView

最近,和几个朋友一起准备做一个关于交易平台的一个项目;
在准备之前,我们的UI设计师给我们设计了一个登录界面,这个登录界面最难之处就是要用户的头像需要圆形的,但Android的组件中并没有现成的View,所以我就去看看了其他大牛们的blog,都是通过自定义View来实现的,所以我就开始边看边学习了一下。

在自定义View之前,需要使用onMeasure()方法测量图片的宽度widthMeasureSpec与高度heightMeasureSpec;然后绘制图片;最后再将自定义View布局上去;
即所有的自定义View都是要:测量—>绘制—>布局;

在我写的自定义圆形View(RoundImageView)中,有个type来决定RoundImageView的类型(round与circle),circle是直接将图片变成圆形图片,round也是将图片变成圆,但是它的四个角的弧度可以设置;
因此,在自定义View之前需要在Android Studio中的values里添加一个attrs.xml,attrs.xml中的内容是:


<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="borderRadius" format="dimension"/>
    <attr name="imageType">
        <enum name="circle" value="0"/>
        <enum name="round" value="1"/>
    </attr>

    <declare-styleable name="RoundImageView">
        <attr name="borderRadius"/>
        <attr name="imageType"/>
    </declare-styleable>
</resources>

然后就是自定义View了:
首先,要实现圆形的图片就需要设置圆角的宽度、画笔、半径、缩放举证、渲染器(使用图片填充形状)、宽度以及圆角范围;
由于我表述有限,直接上代码吧:

public class RoundImageView extends ImageView {

    private int type;                                           //ImageView的类型;
    private static final int TYPE_CIRCLE = 0;                   //圆形图片;
    private static final int TYPE_ROUND = 1;                    //圆角图片;
    private static final int BORDER_RADIUS_DEFAULT = 10;        //默认圆角宽度;
    private int mBorderRadius;                                  //设置圆角宽度;
    private Paint mPaint;                                       //画笔;
    private int mRadius;                                        //半径;
    private Matrix mMatrix;                                     //缩放矩阵;
    private BitmapShader mBitmapshader;                         //渲染器,使用图片填充形状;
    private  int mWidth;                                        //宽度;
    private RectF mRectF;                                       //圆角范围;


    public RoundImageView(Context context) {
        this(context,null);
    }

    public RoundImageView(Context context, AttributeSet attrs) {
        this(context,attrs,0);
    }

    public RoundImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //设置画笔属性;
        mMatrix = new Matrix();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        //获取自定义属性值;
        TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.RoundImageView,defStyleAttr,0);
        int count = array.getIndexCount();
        for(int i = 0;i<count;i++){
            int attr = array.getIndex(i);
            switch (attr){
                case R.styleable.RoundImageView_borderRadius:
                    //获取圆角大小;
                    mBorderRadius = array.getDimensionPixelSize(R.styleable.RoundImageView_borderRadius,
                            (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,BORDER_RADIUS_DEFAULT,getResources().getDisplayMetrics()));
                    break;
                case R.styleable.RoundImageView_imageType:
                    //获取ImageView的类型;
                    type = array.getInt(R.styleable.RoundImageView_imageType,TYPE_CIRCLE);
                    break;
            }
        }
        array.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //如果是圆形,则强制宽高一致,一最小值为准;
        if(type == TYPE_CIRCLE){
            mWidth = Math.min(getMeasuredWidth(),getMeasuredHeight());
            mRadius = mWidth / 2;
            setMeasuredDimension(mWidth,mWidth);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if(getDrawable() == null){
            return ;
        }
        //设置渲染器;
        setShader();
        if(type == TYPE_ROUND){
            canvas.drawRoundRect(mRectF,mBorderRadius,mBorderRadius,mPaint);
        }else{
            canvas.drawCircle(mRadius,mRadius,mRadius,mPaint);
        }
    }

    private void setShader() {
        Drawable drawable = getDrawable();
        if(drawable == null){
            return ;
        }
        Bitmap bitmap = drawableToBitmap(drawable);
        mBitmapshader  = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        float scale = 1.0f;
        if(type == TYPE_ROUND){
            scale = Math.max(getWidth()*1.0f / bitmap.getWidth(),getHeight()*1.0f / bitmap.getHeight());
        }else  if(type == TYPE_CIRCLE){
            //取最小值,如果取最大值的话,则不能覆盖view;
            int bitmapWidth = Math.min(bitmap.getWidth(),getHeight());
            scale = mWidth * 1.0f / bitmapWidth;
        }
        mMatrix.setScale(scale,scale);
        mBitmapshader.setLocalMatrix(mMatrix);
        mPaint.setShader(mBitmapshader);
    }

    private Bitmap drawableToBitmap(Drawable drawable) {
        if(drawable instanceof BitmapDrawable){
            BitmapDrawable bd = (BitmapDrawable) drawable;
            return bd.getBitmap();
        }
        int w = drawable.getIntrinsicWidth();
        int h = drawable.getIntrinsicHeight();
        //创建画布;
        Bitmap bitmap = Bitmap.createBitmap(w,h, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0,0,w,h);
        drawable.draw(canvas);
        return bitmap;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mRectF  = new RectF(0,0,getWidth(),getHeight());
    }

    //对外公布设置borderRadius 的方法;
    public void setBorderRadius(int borderRadius){
        int pxValue = dpTodp(borderRadius);
        if(this.mBorderRadius!= pxValue){
            this.mBorderRadius = pxValue;
            //这时候不需要父布局的onLayout,只需调用onDraw即可;
            invalidate();
        }
    }

    //对外公布设置形状的方法;
    public void setType(int type){
        if(this.type!=type){
            this.type = type;
            if(this.type != TYPE_CIRCLE && this.type != TYPE_ROUND){
                this.type = TYPE_CIRCLE;
            }
            //这个时候改变形状了,就需要调用父布局的onLayout ,那么此 view 的onMeasure方法也会被调用;
            requestLayout();
        }
    }

    public int dpTodp(int val){
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,val,getResources().getDisplayMetrics());
    }
}

最后使用的时候就类似ImageView的那样,只是多了三个设置语句,我使用的时候,嵌套在RelativeLayout中:

<com.our_company.school_second_hand_shop.MyView.RoundImageView
                    android:id="@+id/login_person"
                    android:layout_centerInParent="true"
                    android:layout_width="110dp"
                    android:layout_height="110dp"
                    app:imageType="circle"           //直接将图片变成圆形的;
                    app:borderRadius="90dp"
                    app:imageType="round"            //图片变成圆形时,弧度可以调;
                    android:src="@mipmap/aa"
                    />

运行结果如下:
这里写图片描述

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值