自定义圆角布局和圆角TextView

用到的资源文件,在res下面values文件夹创建attrs.xml资源文件:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
           tools:ignore="ResourceName">

    <!-- 以下是重用attr的正确姿势,一切为了在布局中可以自动提示-->
    <!-- 圆角矩形背景色 -->
    <attr name="rv_backgroundColor" format="color"/>
    <!-- 圆角矩形背景色press -->
    <attr name="rv_backgroundPressColor" format="color"/>
    <!-- 圆角弧度,单位dp-->
    <attr name="rv_cornerRadius" format="dimension"/>
    <!-- 圆角弧度,单位dp-->
    <attr name="rv_strokeWidth" format="dimension"/>
    <!-- 圆角边框颜色-->
    <attr name="rv_strokeColor" format="color"/>
    <!-- 圆角边框颜色press -->
    <attr name="rv_strokePressColor" format="color"/>
    <!-- 文字颜色press-->
    <attr name="rv_textPressColor" format="color"/>
    <!-- 圆角弧度是高度一半-->
    <attr name="rv_isRadiusHalfHeight" format="boolean"/>
    <!-- 圆角矩形宽高相等,取较宽高中大值-->
    <attr name="rv_isWidthHeightEqual" format="boolean"/>
    <!-- 圆角弧度,单位dp,TopLeft-->
    <attr name="rv_cornerRadius_TL" format="dimension"/>
    <!-- 圆角弧度,单位dp,TopRight-->
    <attr name="rv_cornerRadius_TR" format="dimension"/>
    <!-- 圆角弧度,单位dp,BottomLeft-->
    <attr name="rv_cornerRadius_BL" format="dimension"/>
    <!-- 圆角弧度,单位dp,BottomRight-->
    <attr name="rv_cornerRadius_BR" format="dimension"/>
    <!-- 是否有Ripple效果,api21+有效-->
    <attr name="rv_isRippleEnable" format="boolean"/>

    <declare-styleable name="RoundTextView">
        <attr name="rv_backgroundColor"/>
        <attr name="rv_backgroundPressColor"/>
        <attr name="rv_cornerRadius"/>
        <attr name="rv_strokeWidth"/>
        <attr name="rv_strokeColor"/>
        <attr name="rv_strokePressColor"/>
        <attr name="rv_textPressColor"/>
        <attr name="rv_isRadiusHalfHeight"/>
        <attr name="rv_isWidthHeightEqual"/>
        <attr name="rv_cornerRadius_TL"/>
        <attr name="rv_cornerRadius_TR"/>
        <attr name="rv_cornerRadius_BL"/>
        <attr name="rv_cornerRadius_BR"/>
        <attr name="rv_isRippleEnable"/>
    </declare-styleable>

    <declare-styleable name="RoundLinearLayout">
        <attr name="rv_backgroundColor"/>
        <attr name="rv_backgroundPressColor"/>
        <attr name="rv_cornerRadius"/>
        <attr name="rv_strokeWidth"/>
        <attr name="rv_strokeColor"/>
        <attr name="rv_strokePressColor"/>
        <attr name="rv_isRadiusHalfHeight"/>
        <attr name="rv_isWidthHeightEqual"/>
        <attr name="rv_cornerRadius_TL"/>
        <attr name="rv_cornerRadius_TR"/>
        <attr name="rv_cornerRadius_BL"/>
        <attr name="rv_cornerRadius_BR"/>
        <attr name="rv_isRippleEnable"/>
    </declare-styleable>

    <declare-styleable name="RoundRelativeLayout">
        <attr name="rv_backgroundColor"/>
        <attr name="rv_backgroundPressColor"/>
        <attr name="rv_cornerRadius"/>
        <attr name="rv_strokeWidth"/>
        <attr name="rv_strokeColor"/>
        <attr name="rv_strokePressColor"/>
        <attr name="rv_isRadiusHalfHeight"/>
        <attr name="rv_isWidthHeightEqual"/>
        <attr name="rv_cornerRadius_TL"/>
        <attr name="rv_cornerRadius_TR"/>
        <attr name="rv_cornerRadius_BL"/>
        <attr name="rv_cornerRadius_BR"/>
        <attr name="rv_isRippleEnable"/>
    </declare-styleable>

    <declare-styleable name="RoundFrameLayout">
        <attr name="rv_backgroundColor"/>
        <attr name="rv_backgroundPressColor"/>
        <attr name="rv_cornerRadius"/>
        <attr name="rv_strokeWidth"/>
        <attr name="rv_strokeColor"/>
        <attr name="rv_strokePressColor"/>
        <attr name="rv_isRadiusHalfHeight"/>
        <attr name="rv_isWidthHeightEqual"/>
        <attr name="rv_cornerRadius_TL"/>
        <attr name="rv_cornerRadius_TR"/>
        <attr name="rv_cornerRadius_BL"/>
        <attr name="rv_cornerRadius_BR"/>
        <attr name="rv_isRippleEnable"/>
    </declare-styleable>



</resources>

基类RoundViewDelegate :


import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.RippleDrawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;

import com.artvrpro.yiwei.R;


public class RoundViewDelegate {
    private View view;
    private Context context;
    private GradientDrawable gd_background = new GradientDrawable();
    private GradientDrawable gd_background_press = new GradientDrawable();
    private int backgroundColor;
    private int backgroundPressColor;
    private int cornerRadius;
    private int cornerRadius_TL;
    private int cornerRadius_TR;
    private int cornerRadius_BL;
    private int cornerRadius_BR;
    private int strokeWidth;
    private int strokeColor;
    private int strokePressColor;
    private int textPressColor;
    private boolean isRadiusHalfHeight;
    private boolean isWidthHeightEqual;
    private boolean isRippleEnable;
    private float[] radiusArr = new float[8];

    public RoundViewDelegate(View view, Context context, AttributeSet attrs) {
        this.view = view;
        this.context = context;
        obtainAttributes(context, attrs);
    }

    private void obtainAttributes(Context context, AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RoundTextView);
        backgroundColor = ta.getColor(R.styleable.RoundTextView_rv_backgroundColor, Color.TRANSPARENT);
        backgroundPressColor = ta.getColor(R.styleable.RoundTextView_rv_backgroundPressColor, Integer.MAX_VALUE);
        cornerRadius = ta.getDimensionPixelSize(R.styleable.RoundTextView_rv_cornerRadius, 0);
        strokeWidth = ta.getDimensionPixelSize(R.styleable.RoundTextView_rv_strokeWidth, 0);
        strokeColor = ta.getColor(R.styleable.RoundTextView_rv_strokeColor, Color.TRANSPARENT);
        strokePressColor = ta.getColor(R.styleable.RoundTextView_rv_strokePressColor, Integer.MAX_VALUE);
        textPressColor = ta.getColor(R.styleable.RoundTextView_rv_textPressColor, Integer.MAX_VALUE);
        isRadiusHalfHeight = ta.getBoolean(R.styleable.RoundTextView_rv_isRadiusHalfHeight, false);
        isWidthHeightEqual = ta.getBoolean(R.styleable.RoundTextView_rv_isWidthHeightEqual, false);
        cornerRadius_TL = ta.getDimensionPixelSize(R.styleable.RoundTextView_rv_cornerRadius_TL, 0);
        cornerRadius_TR = ta.getDimensionPixelSize(R.styleable.RoundTextView_rv_cornerRadius_TR, 0);
        cornerRadius_BL = ta.getDimensionPixelSize(R.styleable.RoundTextView_rv_cornerRadius_BL, 0);
        cornerRadius_BR = ta.getDimensionPixelSize(R.styleable.RoundTextView_rv_cornerRadius_BR, 0);
        isRippleEnable = ta.getBoolean(R.styleable.RoundTextView_rv_isRippleEnable, true);

        ta.recycle();
    }

    public void setBackgroundColor(int backgroundColor) {
        this.backgroundColor = backgroundColor;
        setBgSelector();
    }

    public void setBackgroundPressColor(int backgroundPressColor) {
        this.backgroundPressColor = backgroundPressColor;
        setBgSelector();
    }

    public void setCornerRadius(int cornerRadius) {
        this.cornerRadius = dp2px(cornerRadius);
        setBgSelector();
    }

    public void setStrokeWidth(int strokeWidth) {
        this.strokeWidth = dp2px(strokeWidth);
        setBgSelector();
    }

    public void setStrokeColor(int strokeColor) {
        this.strokeColor = strokeColor;
        setBgSelector();
    }

    public void setStrokePressColor(int strokePressColor) {
        this.strokePressColor = strokePressColor;
        setBgSelector();
    }

    public void setTextPressColor(int textPressColor) {
        this.textPressColor = textPressColor;
        setBgSelector();
    }

    public void setIsRadiusHalfHeight(boolean isRadiusHalfHeight) {
        this.isRadiusHalfHeight = isRadiusHalfHeight;
        setBgSelector();
    }

    public void setIsWidthHeightEqual(boolean isWidthHeightEqual) {
        this.isWidthHeightEqual = isWidthHeightEqual;
        setBgSelector();
    }

    public void setCornerRadius_TL(int cornerRadius_TL) {
        this.cornerRadius_TL = cornerRadius_TL;
        setBgSelector();
    }

    public void setCornerRadius_TR(int cornerRadius_TR) {
        this.cornerRadius_TR = cornerRadius_TR;
        setBgSelector();
    }

    public void setCornerRadius_BL(int cornerRadius_BL) {
        this.cornerRadius_BL = cornerRadius_BL;
        setBgSelector();
    }

    public void setCornerRadius_BR(int cornerRadius_BR) {
        this.cornerRadius_BR = cornerRadius_BR;
        setBgSelector();
    }

    public int getBackgroundColor() {
        return backgroundColor;
    }

    public int getBackgroundPressColor() {
        return backgroundPressColor;
    }

    public int getCornerRadius() {
        return cornerRadius;
    }

    public int getStrokeWidth() {
        return strokeWidth;
    }

    public int getStrokeColor() {
        return strokeColor;
    }

    public int getStrokePressColor() {
        return strokePressColor;
    }

    public int getTextPressColor() {
        return textPressColor;
    }

    public boolean isRadiusHalfHeight() {
        return isRadiusHalfHeight;
    }

    public boolean isWidthHeightEqual() {
        return isWidthHeightEqual;
    }

    public int getCornerRadius_TL() {
        return cornerRadius_TL;
    }

    public int getCornerRadius_TR() {
        return cornerRadius_TR;
    }

    public int getCornerRadius_BL() {
        return cornerRadius_BL;
    }

    public int getCornerRadius_BR() {
        return cornerRadius_BR;
    }

    protected int dp2px(float dp) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dp * scale + 0.5f);
    }

    protected int sp2px(float sp) {
        final float scale = this.context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (sp * scale + 0.5f);
    }

    private void setDrawable(GradientDrawable gd, int color, int strokeColor) {
        gd.setColor(color);

        if (cornerRadius_TL > 0 || cornerRadius_TR > 0 || cornerRadius_BR > 0 || cornerRadius_BL > 0) {
            /**The corners are ordered top-left, top-right, bottom-right, bottom-left*/
            radiusArr[0] = cornerRadius_TL;
            radiusArr[1] = cornerRadius_TL;
            radiusArr[2] = cornerRadius_TR;
            radiusArr[3] = cornerRadius_TR;
            radiusArr[4] = cornerRadius_BR;
            radiusArr[5] = cornerRadius_BR;
            radiusArr[6] = cornerRadius_BL;
            radiusArr[7] = cornerRadius_BL;
            gd.setCornerRadii(radiusArr);
        } else {
            gd.setCornerRadius(cornerRadius);
        }

        gd.setStroke(strokeWidth, strokeColor);
    }

    public void setBgSelector() {
        StateListDrawable bg = new StateListDrawable();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && isRippleEnable) {
            setDrawable(gd_background, backgroundColor, strokeColor);
            RippleDrawable rippleDrawable = new RippleDrawable(
                    getPressedColorSelector(backgroundColor, backgroundPressColor), gd_background, null);
            view.setBackground(rippleDrawable);
        } else {
            setDrawable(gd_background, backgroundColor, strokeColor);
            bg.addState(new int[]{-android.R.attr.state_pressed}, gd_background);
            if (backgroundPressColor != Integer.MAX_VALUE || strokePressColor != Integer.MAX_VALUE) {
                setDrawable(gd_background_press, backgroundPressColor == Integer.MAX_VALUE ? backgroundColor : backgroundPressColor,
                        strokePressColor == Integer.MAX_VALUE ? strokeColor : strokePressColor);
                bg.addState(new int[]{android.R.attr.state_pressed}, gd_background_press);
            }

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {//16
                view.setBackground(bg);
            } else {
                //noinspection deprecation
                view.setBackgroundDrawable(bg);
            }
        }

        if (view instanceof TextView) {
            if (textPressColor != Integer.MAX_VALUE) {
                ColorStateList textColors = ((TextView) view).getTextColors();
//              Log.d("AAA", textColors.getColorForState(new int[]{-android.R.attr.state_pressed}, -1) + "");
                ColorStateList colorStateList = new ColorStateList(
                        new int[][]{new int[]{-android.R.attr.state_pressed}, new int[]{android.R.attr.state_pressed}},
                        new int[]{textColors.getDefaultColor(), textPressColor});
                ((TextView) view).setTextColor(colorStateList);
            }
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private ColorStateList getPressedColorSelector(int normalColor, int pressedColor) {
        return new ColorStateList(
                new int[][]{
                        new int[]{android.R.attr.state_pressed},
                        new int[]{android.R.attr.state_focused},
                        new int[]{android.R.attr.state_activated},
                        new int[]{}
                },
                new int[]{
                        pressedColor,
                        pressedColor,
                        pressedColor,
                        normalColor
                }
        );
    }
}

圆角相对布局RoundRelativeLayout:


import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;

/** 用于需要圆角矩形框背景的RelativeLayout的情况,减少直接使用RelativeLayout时引入的shape资源文件 */
public class RoundRelativeLayout extends RelativeLayout {
    private RoundViewDelegate delegate;

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

    public RoundRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        delegate = new RoundViewDelegate(this, context, attrs);
    }

    /** use delegate to set attr */
    public RoundViewDelegate getDelegate() {
        return delegate;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (delegate.isWidthHeightEqual() && getWidth() > 0 && getHeight() > 0) {
            int max = Math.max(getWidth(), getHeight());
            int measureSpec = MeasureSpec.makeMeasureSpec(max, MeasureSpec.EXACTLY);
            super.onMeasure(measureSpec, measureSpec);
            return;
        }

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (delegate.isRadiusHalfHeight()) {
            delegate.setCornerRadius(getHeight() / 2);
        }else {
            delegate.setBgSelector();
        }
    }
}

圆角线性布局RoundLinearLayout:


import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;

/** 用于需要圆角矩形框背景的LinearLayout的情况,减少直接使用LinearLayout时引入的shape资源文件 */
public class RoundLinearLayout extends LinearLayout {
    private RoundViewDelegate delegate;

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

    public RoundLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        delegate = new RoundViewDelegate(this, context, attrs);
    }

    /** use delegate to set attr */
    public RoundViewDelegate getDelegate() {
        return delegate;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (delegate.isWidthHeightEqual() && getWidth() > 0 && getHeight() > 0) {
            int max = Math.max(getWidth(), getHeight());
            int measureSpec = MeasureSpec.makeMeasureSpec(max, MeasureSpec.EXACTLY);
            super.onMeasure(measureSpec, measureSpec);
            return;
        }

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (delegate.isRadiusHalfHeight()) {
            delegate.setCornerRadius(getHeight() / 2);
        }else {
            delegate.setBgSelector();
        }
    }
}

圆角TextView RoundTextView:


import android.content.Context;
import android.util.AttributeSet;

import androidx.appcompat.widget.AppCompatTextView;

/** 用于需要圆角矩形框背景的TextView的情况,减少直接使用TextView时引入的shape资源文件 */
    public class RoundTextView extends AppCompatTextView {
    private RoundViewDelegate delegate;

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

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

    public RoundTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        delegate = new RoundViewDelegate(this, context, attrs);
    }

    /** use delegate to set attr */
    public RoundViewDelegate getDelegate() {
        return delegate;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (delegate.isWidthHeightEqual() && getWidth() > 0 && getHeight() > 0) {
            int max = Math.max(getWidth(), getHeight());
            int measureSpec = MeasureSpec.makeMeasureSpec(max, MeasureSpec.EXACTLY);
            super.onMeasure(measureSpec, measureSpec);
            return;
        }

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (delegate.isRadiusHalfHeight()) {
            delegate.setCornerRadius(getHeight() / 2);
        } else {
            delegate.setBgSelector();
        }
    }
}

=================分割线================

圆角渐变色矩形:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle"><!--rectangle :矩形-->

    <!--
android:startColor="#aa000000"  渐变起始色值
android:centerColor=""      渐变中间色值
android:endColor="#ffffffff"    渐变结束颜色
android:angle="45"      渐变的方向 默认为0 从做向右 ,90时从下向上 必须为45的整数倍
android:type="radial"       渐变类型 有三种 线性linear 放射渐变radial 扫描线性渐变sweep
android:centerX="0.5"       渐变中心相对X坐标只有渐变类型为放射渐变时有效
android:centerY="0.5"       渐变中心相对Y坐标只有渐变类型为放射渐变时有效
android:gradientRadius="100"    渐变半径 非线性放射有效
 -->


    <corners android:radius="10dp" />
    <gradient
        android:startColor="#7167FF"

        android:endColor="#A1DAFF"
        android:angle="90"
        android:type="linear"
        />
    <!--android:centerColor="#0c8ef9"-->
</shape>

渐变色圆形:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval"><!-- oval:圆形-->
    <solid android:color="#4A6DED" />
    <size
        android:width="66dp"
        android:height="66dp"></size>
    <!--
android:startColor="#aa000000"  渐变起始色值
android:centerColor=""      渐变中间色值
android:endColor="#ffffffff"    渐变结束颜色
android:angle="45"      渐变的方向 默认为0 从做向右 ,90时从下向上 必须为45的整数倍
android:type="radial"       渐变类型 有三种 线性linear 放射渐变radial 扫描线性渐变sweep
android:centerX="0.5"       渐变中心相对X坐标只有渐变类型为放射渐变时有效
android:centerY="0.5"       渐变中心相对Y坐标只有渐变类型为放射渐变时有效
android:gradientRadius="100"    渐变半径 非线性放射有效
 -->

    <gradient
        android:centerX="0.5"
        android:centerY="0.5"
        android:startColor="#4A6DED"
        android:endColor="#A1DAFF"
        android:angle="90"
        android:type="radial"
        android:gradientRadius="100"
        />
    <!--android:centerColor="#0c8ef9"-->
</shape>

圆角纯色带边框矩形:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- 设置圆角 -->
    <corners android:radius="30dp" />
    <!--  设置边框的 厚度和颜色-->
    <stroke
        android:width="2dp"
        android:color="#ffffff" />
    <solid android:color="#FFC627" />
</shape>

猜你喜欢

转载自blog.csdn.net/qq_38306233/article/details/135387861
今日推荐