用到的资源文件,在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>