Android深入

Android 圆角ImageView实现

2021-11-17  本文已影响0人  小仙女喂得猪呀

由于项目之前的CircleImageView的实现方式是针对bitmap去操作的,不是很优雅,且在用glide加载gif的时候会偶现一个bitmap的转换异常,所以借此机会尽可能优雅的实现了一个专用的圆角ImageView,分享给各位大佬们,如有不当之处,请多多指点

for kotlin

class CircleImageView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : AppCompatImageView(context, attrs) {


    private var mRadius: Int = 0
    private val viewOutlineProvider: ViewOutlineProvider by lazy {
        @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
        object : ViewOutlineProvider() {
            override fun getOutline(view: View?, outline: Outline?) {
                val width = width
                val height = height
                outline?.setRoundRect(0, 0, width, height, mRadius.toFloat())
            }

        }
    }
    private var path: Path?
    private var rect: RectF?


    init {
        val obtainStyledAttributes =
            context.obtainStyledAttributes(attrs, R.styleable.CircleImageViewV3)
        obtainStyledAttributes.let {
            mRadius =
                it.getInt(
                    R.styleable.CircleImageViewV3_CustomizeRadiusV3,
                    (getContext().resources.getDimension(R.dimen.dp_10)).toInt()
                )
            it.recycle()
            path = Path()
            rect = RectF()
            if (ModuleUtils.isRoundCornerMask()) { //只对小度做圆角处理
                setRound(mRadius)
            }
        }
    }

    //设置圆角图片
    fun setRound(radius: Int) = apply {
        val isChange = radius != mRadius
        mRadius = radius
        if (mRadius != 0) {
            if (Build.VERSION_CODES.LOLLIPOP <= Build.VERSION.SDK_INT) {
                outlineProvider = viewOutlineProvider
                clipToOutline = true

            }
            val width = width.toFloat()
            val height = height.toFloat()
            rect?.set(0f, 0f, width, height)
            path?.reset()
            rect?.let { path?.addRoundRect(it,mRadius.toFloat(),mRadius.toFloat(),Path.Direction.CW) }
        } else {
            if (Build.VERSION_CODES.LOLLIPOP <= Build.VERSION.SDK_INT) {
                clipToOutline = false
            }
        }

        if (isChange) {
            if (Build.VERSION_CODES.LOLLIPOP <= Build.VERSION.SDK_INT) {
                invalidateOutline()
            }
        }

    }

    override fun draw(canvas: Canvas?){
        var clip = false
        if (Build.VERSION_CODES.LOLLIPOP > Build.VERSION.SDK_INT && mRadius > 0) {
            clip = true
            canvas?.save()
            path?.let { canvas?.clipPath(it) }

        }
        super.draw(canvas)
        if (clip) {
            canvas?.restore()
        }
    }


}

for java

package com.wj.motiondemo;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Outline;
import android.graphics.Path;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;

/**
 * @Author : jiyajie
 * @Time : On 2021/11/23 09:45
 * @Description : CircleImageViewV2
 */
public class CircleImageViewV2 extends AppCompatImageView {

    private int mRadius;
    private Path mPath;
    private RectF mRectF;
    private ViewOutlineProvider viewOutlineProvider;

    public CircleImageViewV2(@NonNull Context context) {
        this(context, null);
    }

    public CircleImageViewV2(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CircleImageViewV2(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleImageViewV2);
        mRadius = (int) typedArray.getDimension(R.styleable.CircleImageViewV2_CustomizeRadiusV2, 0f);
        typedArray.recycle();
        setmRadius(mRadius);
    }

    //更新图片圆角
    public void setmRadius(int radius) {
        boolean isChange = radius != mRadius;
        mRadius = radius;
        if (mPath == null) {
            mPath = new Path();
        }
        if (mRectF == null) {
            mRectF = new RectF();
        }
        if (mRadius != 0) {
            if (Build.VERSION_CODES.LOLLIPOP <= Build.VERSION.SDK_INT) {
                if (viewOutlineProvider == null) {
                    viewOutlineProvider = new ViewOutlineProvider() {
                        @Override
                        public void getOutline(View view, Outline outline) {
                            int width = getWidth();
                            int height = getHeight();
                            outline.setRoundRect(0,0,width,height,mRadius);
                        }
                    };
                }
                setOutlineProvider(viewOutlineProvider);
                setClipToOutline(true);
            }
            mRectF.set(0, 0, getWidth(), getHeight());
            mPath.reset();
            mPath.addRoundRect(mRectF, mRadius, mRadius, Path.Direction.CW);
        } else {
            if (Build.VERSION_CODES.LOLLIPOP <= Build.VERSION.SDK_INT) {
                setClipToOutline(false);
            }
        }

        if (isChange) {
            if (Build.VERSION_CODES.LOLLIPOP <= Build.VERSION.SDK_INT) {
                invalidateOutline();
            }
        }

    }


    @Override
    public void draw(Canvas canvas) {
        boolean clip = false;
        if (Build.VERSION_CODES.LOLLIPOP > Build.VERSION.SDK_INT && mRadius > 0) {
            clip = true;
            canvas.save();
            canvas.clipPath(mPath);
        }
        super.draw(canvas);
        if (clip) {
            canvas.restore();
        }
    }
}

效果如图:


WechatIMG8222.png
上一篇下一篇

猜你喜欢

热点阅读