自定义label组件

自定义label组件

支持边框绘制
支持shape背景(按指定圆角裁剪,矩形,圆角矩,圆形),支持指定角圆角
支持自定义阴影(颜色,偏移,深度)
边框颜色支持状态选择器

预览

在这里插入图片描述

核心绘制辅助类
public class LabelHelper {
    private final Paint paint;
    private Paint shadowPaint;
    private final float[] radiusList = new float[8];// 矩阵四角圆角 两个一组分别为一角的x轴半径y轴半径  四组分别为 上左 上右  下右  下左
    private final Rect rect;
    private final Path path;
    private final RectF rectF;
    private float strokeWidth;
    private ColorStateList strokeColor;
    private boolean hasRadius;//是否有圆角
    private int shadowColor;//是否有阴影
    private float shadowRadius;
    private float shadowDx;
    private float shadowDy;
    private Float contentInsetLeft = null;
    private Float contentInsetRight = null;
    private int defStrokeColor;

    LabelHelper(View view, Context context, AttributeSet attrs) {
        this(view, context, attrs, Color.TRANSPARENT);
    }

    LabelHelper(View view, Context context, AttributeSet attrs, @ColorInt int defStrokeColor) {
        this.defStrokeColor = defStrokeColor;
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.LabelView);
        // 圆角
        float radius = array.getDimension(R.styleable.LabelView_android_radius, 0);
        float topLeftRadius = array.getDimension(R.styleable.LabelView_android_topLeftRadius, radius);
        float topRightRadius = array.getDimension(R.styleable.LabelView_android_topRightRadius, radius);
        float bottomLeftRadius = array.getDimension(R.styleable.LabelView_android_bottomLeftRadius, radius);
        float bottomRightRadius = array.getDimension(R.styleable.LabelView_android_bottomRightRadius, radius);
        // 阴影
        int shadowColor = array.getColor(R.styleable.LabelView_android_shadowColor, Color.TRANSPARENT);
        float shadowRadius = array.getFloat(R.styleable.LabelView_android_shadowRadius, 0.0f);
        float shadowDx = array.getFloat(R.styleable.LabelView_android_shadowDx, 0.0f);
        float shadowDy = array.getFloat(R.styleable.LabelView_android_shadowDy, 0.0f);

        if (array.hasValue(R.styleable.LabelView_android_contentInsetLeft)) {
            contentInsetLeft = array.getDimension(R.styleable.LabelView_android_contentInsetLeft, 0);
        }
        if (array.hasValue(R.styleable.LabelView_android_contentInsetRight)) {
            contentInsetRight = array.getDimension(R.styleable.LabelView_android_contentInsetRight, 0);
        }

        int anInt = array.getInt(R.styleable.LabelView_fillType, 1);
		
		// 边框
        strokeWidth = array.getDimension(R.styleable.LabelView_borderWidth, 0);
        try {
            strokeColor = array.getColorStateList(R.styleable.LabelView_borderColor);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (strokeColor == null) {
            strokeColor = ColorStateList.valueOf(array.getColor(R.styleable.LabelView_borderColor, this.defStrokeColor));
        }
        view.setSelected(array.getBoolean(R.styleable.LabelView_selected, false));
        array.recycle();
        
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(getPaintStyle(anInt));
        paint.setStrokeWidth(strokeWidth);
        rectF = new RectF();
        rect = new Rect();
        path = new Path();
        setRadiusPx(view, topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius);
        view.setLayerType(LAYER_TYPE_HARDWARE, null);
        setShadow(shadowColor, shadowRadius, shadowDx, shadowDy);
    }

	// 设置阴影画笔
    private void setShadow(int shadowColor, float shadowRadius, float shadowDx, float shadowDy) {
        if (shadowPaint == null) {
            shadowPaint = new Paint();
            shadowPaint.setAntiAlias(true);
            shadowPaint.setStyle(Paint.Style.FILL);
        }
        this.shadowRadius = Math.max(shadowRadius, 0);
        this.shadowDx = shadowDx;
        this.shadowDy = shadowDy;
        this.shadowColor = shadowColor;
        shadowPaint.setColor(shadowColor);
        shadowPaint.setShadowLayer(this.shadowRadius, this.shadowDx, this.shadowDy, shadowColor);
    }

    private Paint.Style getPaintStyle(int type) {
        return switch (type) {
            case 0 -> Paint.Style.FILL;
            case 2 -> Paint.Style.FILL_AND_STROKE;
            default -> Paint.Style.STROKE;
        };
    }

    void setStrokeWidth(int dp) {
        strokeWidth = SizeUtils.dp2px(dp);
        paint.setStrokeWidth(strokeWidth);
    }

    void setStrokeColor(@ColorInt int boundColor) {
        this.strokeColor = ColorStateList.valueOf(boundColor);
    }

    void setFillType(Paint.Style style) {
        paint.setStyle(style);
    }

    void setRadiusPx(View view, float topLeft, float topRight, float bottomRight, float bottomLeft) {
        radiusList[0] = topLeft;
        radiusList[1] = topLeft;
        radiusList[2] = topRight;
        radiusList[3] = topRight;
        radiusList[4] = bottomRight;
        radiusList[5] = bottomRight;
        radiusList[6] = bottomLeft;
        radiusList[7] = bottomLeft;
        hasRadius = topLeft > 0 || topRight > 0 || bottomRight > 0 || bottomLeft > 0;
        float offsetPaddingL = 0;
        float offsetPaddingR = 0;
        float offsetPaddingT = 0;
        float offsetPaddingB = 0;
        boolean autoInsetLeft = contentInsetLeft == null;
        boolean autoInsetRight = contentInsetRight == null;
        if (hasRadius) {
            if (autoInsetLeft) {
                offsetPaddingL = Math.max(topLeft, bottomLeft) / 2f;
            } else if (contentInsetLeft != 0) {
                offsetPaddingL = contentInsetLeft;
            }
            if (autoInsetRight) {
                offsetPaddingR = Math.max(topRight, bottomRight) / 2f;
            } else if (contentInsetRight != 0) {
                offsetPaddingR = contentInsetRight;
            }
        }

        if (isDrawBorder(view)) {
            offsetPaddingL = Math.max(offsetPaddingL, strokeWidth);
            offsetPaddingR = Math.max(offsetPaddingL, strokeWidth);
            offsetPaddingT = strokeWidth;
            offsetPaddingB = strokeWidth;
        }

        view.setPadding((int) Math.max(view.getPaddingLeft(), offsetPaddingL),
                (int) Math.max(view.getPaddingTop(), offsetPaddingT),
                (int) Math.max(view.getPaddingRight(), offsetPaddingR),
                (int) Math.max(view.getPaddingBottom(), offsetPaddingB));
        setStroke();
        view.invalidate();
    }

    private void setStroke() {
        if (hasRadius) {
            paint.setStrokeCap(Paint.Cap.ROUND);
            paint.setStrokeJoin(Paint.Join.ROUND);
        } else {
            paint.setStrokeCap(Paint.Cap.BUTT);
            paint.setStrokeJoin(Paint.Join.MITER);
        }
    }

    void draw(Canvas canvas, View view) {
        view.getDrawingRect(rect);
        rectF.set(rect);
        if (hasRadius) {
            path.reset();
            path.addRoundRect(rectF, radiusList, Path.Direction.CW);
            path.close();
            canvas.clipPath(path);
        }

        if (isDrawShadow()) {
            path.reset();
            rectF.left += Math.max(shadowRadius - shadowDx, 0);
            rectF.right -= Math.max(shadowRadius + shadowDx, 0);
            rectF.top += Math.max(shadowRadius - shadowDy, 0);
            rectF.bottom -= Math.max(shadowRadius + shadowDy, 0);
            path.addRoundRect(rectF, radiusList, Path.Direction.CW);
            path.close();
            canvas.drawPath(path, shadowPaint);
            canvas.save();
            canvas.clipPath(path);
        }
    }

    void onDraw(Canvas canvas, View view) {
         if (isDrawBorder(view)) {
            Paint.Style style = paint.getStyle();
            if (style != Paint.Style.STROKE) {
                canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
            }
            paint.setColor(getBoundColor(view));
            canvas.save();
            if (style != Paint.Style.FILL) {
                path.reset();
                rectF.left += (strokeWidth / 2f - 0.5f);
                rectF.top += (strokeWidth / 2f - 0.5f);
                rectF.right -= strokeWidth / 2f;
                rectF.bottom -= strokeWidth / 2f;
                path.addRoundRect(rectF, radiusList, Path.Direction.CW);
                path.close();
            }
            canvas.drawPath(path, paint);
            canvas.restore();
        }
    }

    Paint getPaint() {
        return paint;
    }

    public Rect getRect() {
        return rect;
    }

    public Path getPath() {
        return path;
    }

    public RectF getRectF() {
        return rectF;
    }

    public float getStrokeWidth() {
        return strokeWidth;
    }

    public boolean isHasRadius() {
        return hasRadius;
    }

    private int getBoundColor(View view) {
        int color = this.defStrokeColor;
        if (strokeColor != null) {
            if (strokeColor.isStateful()) {
                color = strokeColor.getColorForState(view.getDrawableState(), strokeColor.getDefaultColor());
            } else {
                color = strokeColor.getDefaultColor();
            }
        }
        return color;
    }

    private boolean isDrawBorder(View view) {
        return strokeWidth > 0 && getBoundColor(view) != Color.TRANSPARENT;
    }

    private boolean isDrawShadow() {
        return shadowPaint != null && shadowColor != Color.TRANSPARENT && shadowRadius > 0;
    }
}

自定义控件示例
public class LabelFrameLayout extends FrameLayout {
    private LabelHelper helper;

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

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

    public LabelFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setWillNotDraw(false);
        helper = new LabelHelper(this, context, attrs);
    }

    public void setFillType(Paint.Style style) {
        if (helper != null && helper.getPaint() != null) {
            helper.setFillType(style);
            invalidate();
        }
    }

    public void setStrokeColor(@ColorInt int boundColor) {
        if (helper != null) {
            helper.setStrokeColor(boundColor);
            invalidate();
        }
    }

    public void setStrokeColorRes(@ColorRes int colorRes) {
        if (helper != null) {
            helper.setStrokeColor(getResources().getColor(colorRes));
            invalidate();
        }
    }

    public void setStrokeWidth(int dp) {
        if (helper != null && helper.getPaint() != null) {
            helper.setStrokeWidth(dp);
            invalidate();
        }
    }

    public void setRadius(int radiusDp) {
        setRadiusPx(SizeUtils.dp2px(radiusDp));
    }

    public void setRadiusPx(float radius) {
        setRadiusPx(radius, radius, radius, radius);
    }

    public void setRadius(float topLeft, float topRight, float bottomRight, float bottomLeft) {
        setRadiusPx(SizeUtils.dp2px(topLeft), SizeUtils.dp2px(topRight), SizeUtils.dp2px(bottomRight), SizeUtils.dp2px(bottomLeft));
    }

    public void setRadiusPx(float topLeft, float topRight, float bottomRight, float bottomLeft) {
        if (helper != null) {
            helper.setRadiusPx(this, topLeft, topRight, bottomRight, bottomLeft);
        }
    }

    @Override
    public void invalidate() {
        if (isLaidOut()) {
            super.invalidate();
        }
    }

    @Override
    public void draw(Canvas canvas) {
        if (helper != null) {
            helper.draw(canvas, this);
        }
        super.draw(canvas);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (helper != null) {
            helper.onDraw(canvas, this);
        }
        super.onDraw(canvas);
    }
}
xml使用示例
<包名.LabelFrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="100dp"
        android:layout_marginBottom="10dp"
        android:background="@color/subColorGray"
        app:borderColor="@color/red"
        app:borderWidth="1dp"
        android:radius="20dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="阿迪斯发斯蒂芬" />
    </包名.LabelFrameLayout>
  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值