android 快速实现 圆角矩形控件 及 圆形控件

1.自定义RoundImageView

java 复制代码
package com.examle.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.ImageView;

import androidx.annotation.ColorInt;
import androidx.annotation.Dimension;
import androidx.annotation.Nullable;

import com.examlpe.R;

public class RoundImageView extends ImageView {
    private String TGA=RoundImageView.class.getSimpleName();
    private final PorterDuffXfermode xfermode=new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP);//绘制模式
    private final Paint mPaint;//实体paint
    private final Paint mStrokePaint;//描边paint
    private int mRadius;//圆角值
    private int mStrokeWidthColor;//描边颜色
    private int mStrokeWidth;//描边宽度
    private boolean mIsCircle;//true-圆形模式,false-圆角矩形模式

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

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

    public RoundImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public RoundImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView);
        mStrokeWidthColor = a.getColor(R.styleable.RoundImageView_riv_stroke_color, Color.WHITE);
        mStrokeWidth = a.getDimensionPixelSize(R.styleable.RoundImageView_riv_stroke_width, 0);
        mRadius = a.getDimensionPixelSize(R.styleable.RoundImageView_riv_round_radius, 0);
        mIsCircle = a.getBoolean(R.styleable.RoundImageView_riv_circle, false);
        a.recycle();

        mPaint = new Paint();
        mPaint.setAntiAlias(true);//抗锯齿
        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.FILL);

        mStrokePaint = new Paint();
        mStrokePaint.setAntiAlias(true);//抗锯齿
        mStrokePaint.setStyle(Paint.Style.STROKE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int layerId = canvas.saveLayer(0, 0, getWidth(), getHeight(), null);//保存图层
        super.onDraw(canvas);
        Drawable src = getDrawable();
        int tmpBpW = getWidth() - getPaddingLeft() - getPaddingRight();//位图宽度,必须大于0
        int tmpBpH = getHeight() - getPaddingTop() - getPaddingBottom();//位图高度,必须大于0
        if (src != null && getWidth() > 0 && getHeight() > 0 && tmpBpW>0 && tmpBpH>0) {
            Bitmap tmpBp = Bitmap.createBitmap(tmpBpW, tmpBpH, Bitmap.Config.ARGB_8888);
            Canvas tmpCv = new Canvas(tmpBp);//tmpBp画布
            float tmpR = Math.min(tmpBp.getWidth(), tmpBp.getHeight()) * 0.5f;//取最小宽度
            if (mIsCircle) {//圆形模式
                tmpCv.drawCircle(tmpR, tmpR, tmpR, mPaint);//绘制圆形
            } else {//圆角矩形模式
                tmpCv.drawRoundRect(0, 0, tmpBp.getWidth(), tmpBp.getHeight(), mRadius, mRadius, mPaint);//绘制圆角矩形
            }
            mPaint.setXfermode(xfermode);//绘制模式
            canvas.drawBitmap(tmpBp, getPaddingLeft(), getPaddingTop(), mPaint);//绘制位图

            if (mStrokeWidth > 0) {//描边
                mStrokePaint.setColor(mStrokeWidthColor);//描边颜色
                mStrokePaint.setStrokeWidth(mStrokeWidth);//描边宽度
                if (mIsCircle) {//圆形模式
                    canvas.drawCircle(getPaddingLeft()+tmpR, getPaddingTop()+tmpR, tmpR-mStrokeWidth*0.5f, mStrokePaint);
                } else {//圆角矩形模式
                    canvas.drawRoundRect(getPaddingLeft()+mStrokeWidth*0.5f, getPaddingTop()+mStrokeWidth*0.5f, getWidth() - getPaddingRight()-mStrokeWidth*0.5f, getHeight() - getPaddingBottom()-mStrokeWidth*0.5f, mRadius-mStrokeWidth*0.5f, mRadius-mStrokeWidth*0.5f, mStrokePaint);//绘制圆角
                }
            }
        }
        canvas.restoreToCount(layerId);//恢复图层
    }

    /**
     * 圆角值 dp
     * @param dpValue
     */
    public void setRadius(@Dimension int dpValue) {
        this.mRadius =(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dpValue,getResources().getDisplayMetrics());
        invalidate();
    }

    /**
     * 描边颜色
     * @param strokeWidthColor
     */
    public void setStrokeWidthColor(@ColorInt int strokeWidthColor) {
        this.mStrokeWidthColor = strokeWidthColor;
        invalidate();
    }

    /**
     * 描边宽度 dp
     * @param dpValue
     */
    public void setStrokeWidth(@Dimension int dpValue) {
        this.mStrokeWidth =(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dpValue,getResources().getDisplayMetrics());
        invalidate();
    }

    /**
     * 圆角矩形 或 圆形控件
     * @param isCircle
     */
    public void setCircle(boolean isCircle) {
        this.mIsCircle = isCircle;
        invalidate();
    }
}

2.新建attrs.xml 文件,路径 res/values/attrs.xml

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="RoundImageView">
        <attr name="riv_stroke_width" format="dimension" />
        <attr name="riv_stroke_color" format="color" />
        <attr name="riv_round_radius" format="dimension" />
        <attr name="riv_circle" format="boolean"/>
    </declare-styleable>
</resources>

3.布局使用:圆角矩形

XML 复制代码
        <com.examlpe.widget.RoundImageView
            android:id="@+id/riv"
            android:layout_width="180dp"
            android:layout_height="180dp"
            app:riv_circle="false"
            android:scaleType="fitXY"
            app:riv_round_radius="20dp"
            app:riv_stroke_width="2dp"
            app:riv_stroke_color="@color/white"
            android:src="@mipmap/ic_launcher" />

4.布局使用:圆形控件

XML 复制代码
        <com.examlpe.widget.RoundImageView
            android:id="@+id/riv"
            android:layout_width="180dp"
            android:layout_height="180dp"
            app:riv_circle="true"
            android:scaleType="fitXY"
            app:riv_stroke_width="2dp"
            app:riv_stroke_color="@color/white"
            android:src="@mipmap/ic_launcher" />
相关推荐
HLC++7 小时前
Linux的进程间通信
android·linux·服务器
爱笑鱼11 小时前
Binder(二):AIDL 生成的 Proxy、Stub 和 Parcel 到底在做什么?
android
爱笑鱼11 小时前
Binder(一):一次方法调用,究竟怎样跨进程执行?
android
壮哥_icon12 小时前
【Android 系统开发】使用 BAT 脚本高效自动化管理 /system/priv-app/ 系统应用(安装与卸载)
android·运维·自动化
用户693717500138413 小时前
Claude Code终端日志Token占用实测:一个过滤器砍掉60%-90%
android·前端·后端
蝉蜕日记14 小时前
AccumuPDF高级版 v2.57 | 视图文转换PDF,合并分割压缩
android·智能手机·pdf·生活·软件需求
吐了啊取名字太难14 小时前
美颜系统AI修图本地跑并支持Mac、win、安卓、iOS不卡顿
android·人工智能·windows·数码相机·mac·ai编程
阿pin15 小时前
Android随笔-Retrofit
android·retrofit
想取一个与众不同的名字好难15 小时前
安卓自定义颜色选择器
android
我命由我1234516 小时前
Android 开发问题:java.lang.NoSuchMethodError:No virtual method readAllBytes()
android·java·java-ee·kotlin·android studio·android-studio·android runtime