声明
本文并非教程, 而是笔记, 不会对知识点一个一个的解释, 当然如果能帮到小伙伴, 我也会感到很欣慰, 有好的意见以及方案, 可以回复
目的
免除编写 selector, 很大程度的减少 xml 文件, 以及 drawable 的整洁, 减少 apk 体积
可拓展性, 其他特殊按钮继承 CommonButton 可以轻松拓展
方便全栈样式统一
知识点
GradientDrawable 对应 xml<shape > 节点
StateListDrawable 对应 xml<selector > 节点
ColorStateList 对应 xml color <selector > 节点
GradientDrawable 以及 xml 比较
xml 表示
- <?xml version="1.0" encoding="utf-8"?>
- <!--
- android:shape=["rectangle" | "oval" | "line" | "ring"]
- shape 的形状, 默认为矩形, 可以设置为矩形(rectangle), 椭圆形(oval), 线(line), 环形(ring)
- 下面的属性只有在 android:shape="ring 时可用:
- android:innerRadius 内环的半径.
- android:innerRadiusRatio 浮点型, 以环的宽度比率来表示内环的半径,
- 例如, 如果 android:innerRadiusRatio, 表示内环半径等于环的宽度除以 5, 这个值是可以被覆盖的, 默认为 9.
- android:thickness 环的厚度
- android:thicknessRatio 浮点型, 以环的宽度比率来表示环的厚度, 例如, 如果 android:thicknessRatio="2",
- 那么环的厚度就等于环的宽度除以 2. 这个值是可以被 android:thickness 覆盖的, 默认值是 3.
- android:useLevel boolean 值, 如果当做是 LevelListDrawable 使用时值为 true, 否则为 false.
- -->
- <shape xmlns:Android="http://schemas.android.com/apk/res/android"
- Android:shape="rectangle">
- <!-- 宽度和高度
- android:width 整型 宽度
- android:height 整型 高度
- -->
- <size
- Android:width="50dp"
- Android:height="50dp"/>
- <!-- 圆角
- android:radius 整型 半径
- android:topLeftRadius 整型 左上角半径
- android:topRightRadius 整型 右上角半径
- android:bottomLeftRadius 整型 左下角半径
- android:bottomRightRadius 整型 右下角半径
- -->
- <corners
- Android:radius="10dp"/><!-- 设置圆角半径, 可以分别设置 4 个角 -->
- <!-- 渐变, 这个设置之后一般就不要设置 solid 填充色了
- android:startColor 颜色值 起始颜色
- android:endColor 颜色值 结束颜色
- android:centerColor 整型 渐变中间颜色, 即开始颜色与结束颜色之间的颜色
- android:angle 整型
- 渐变角度(PS: 当 angle=0 时, 渐变色是从左向右. 然后逆时针方向转, 当 angle=90 时为从下往上. angle 必须为 45 的整数倍)
- android:type ["linear" | "radial" | "sweep"] 渐变类型(取值: linear,radial,sweep)
- linear 线性渐变, 这是默认设置
- radial 放射性渐变, 以开始色为中心.
- sweep 扫描线式的渐变.
- android:useLevel ["true" | "false"]
- 如果要使用 LevelListDrawable 对象, 就要设置为 true. 设置为 true 无渐变. false 有渐变色
- android:gradientRadius 整型
- 渐变色半径. 当 android:type="radial" 时才使用. 单独使用 android:type="radial" 会报错.
- android:centerX 整型 渐变中心 X 点坐标的相对位置
- android:centerY 整型 渐变中心 Y 点坐标的相对位置
- -->
- <gradient
- Android:startColor="@android:color/white"
- Android:centerColor="@android:color/black"
- Android:endColor="@android:color/black"
- Android:useLevel="true"
- Android:angle="45"
- Android:type="radial"
- Android:centerX="0"
- Android:centerY="0"
- Android:gradientRadius="90"/>
- <!-- 间隔
- 内边距, 即内容与边的距离
- android:left 整型 左内边距
- android:top 整型 上内边距
- android:right 整型 右内边距
- android:bottom 整型 下内边距
- -->
- <padding
- Android:left="5dp"
- Android:top="5dp"
- Android:right="5dp"
- Android:bottom="5dp"/>
- <!-- 填充
- android:color 颜色值 填充颜色
- -->
- <solid
- Android:color="@android:color/white"/><!-- 填充的颜色 -->
- <!-- 描边
- android:width 整型 描边的宽度
- android:color 颜色值 描边的颜色
- android:dashWidth 整型 表示描边的样式是虚线的宽度, 值为 0 时, 表示为实线. 值大于 0 则为虚线.
- android:dashGap 整型 表示描边为虚线时, 虚线之间的间隔 即 "- - - -"
- -->
- <stroke
- Android:width="1dp" <!-- 边框宽度 -->
- Android:color="@android:color/black"
- Android:dashWidth="1dp"
- Android:dashGap="2dp"/>
- </shape>
GradientDrawable 表示
- View view = null; // 这个 view 是你需要设置背景的 view
- int strokeWidth = 1; // 1dp 边框宽度
- int roundRadius = 5; // 5dp 圆角半径
- int strokeColor = Color.parseColor("#FFFF0000");// 边框颜色
- int fillColor = Color.parseColor("#FF00FF00"); // 内部填充颜色
- GradientDrawable gd = new GradientDrawable();// 创建 drawable
- gd.setColor(fillColor);
- gd.setCornerRadius(roundRadius);
- gd.setStroke(strokeWidth, strokeColor);
- gd.setGradientType(GradientDrawable.RECTANGLE);
- view.setBackgroundDrawable(gd);
- // 创建渐变的 shape drawable
- int colors[] = {
- 0xff255779 , 0xff3e7492, 0xffa6c0cd
- };// 分别为开始颜色, 中间夜色, 结束颜色
- GradientDrawable gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, colors);
- view.setBackgroundDrawable(gd);
StateListDrawable 以及 xml 比较
xml 表示
- <?xml version="1.0" encoding="utf-8"?>
- <selector xmlns:Android="http://schemas.android.com/apk/res/android">
- <item Android:drawable="@drawable/mPressedBackground" Android:state_enabled="true" Android:state_pressed="true" />
- <item Android:drawable="@drawable/mPressedBackground" Android:state_enabled="true" Android:state_focused="true" />
- <item Android:drawable="@drawable/mUnableBackground" Android:state_enabled="true" />
- <item Android:drawable="@drawable/mNormalBackground" Android:state_enabled="false" />
- </selector>
StateListDrawable 表示
- states = new int[4][];
- //pressed, focused, normal, unable
- states[0] = new int[] { Android.R.attr.state_enabled, Android.R.attr.state_pressed };
- states[1] = new int[] { Android.R.attr.state_enabled, Android.R.attr.state_focused };
- states[2] = new int[] { Android.R.attr.state_enabled };
- states[3] = new int[] { -Android.R.attr.state_enabled};
- StateListDrawable mStateBackground = new StateListDrawable();
- // 设置背景颜色
- mStateBackground.addState(states[0], mPressedBackground);
- mStateBackground.addState(states[1], mPressedBackground);
- mStateBackground.addState(states[3], mUnableBackground);
- mStateBackground.addState(states[2], mNormalBackground);
ColorStateList 以及 xml 比较
xml 表示
- <?xml version="1.0" encoding="utf-8"?>
- <selector xmlns:Android="http://schemas.android.com/apk/res/android">
- <item Android:color="@color/mPressedTextColor" Android:state_enabled="true" Android:state_pressed="true"/>
- <item Android:color="@color/mPressedTextColor" Android:state_enabled="true" Android:state_focused="true"/>
- <item Android:color="@color/mNormalTextColor" Android:state_enabled="true"/>
- <item Android:color="@color/mUnableTextColor" Android:state_enabled="false"/>
- </selector>
ColorStateList 表示
- // 设置字体颜色
- int[] colors = new int[] {mPressedTextColor, mPressedTextColor, mNormalTextColor, mUnableTextColor};
- ColorStateList mTextColorStateList = new ColorStateList(states, colors);
掌握好这个几个知识点后写一个自定义 Button 就很简单了, 配合之前常用的 xml 去理解 很好理解的 下面就是 CommonButton 的源代码 不到 150 行搞定一个基础的通用按钮, 希望对你的项目有所帮助
- CommonButton
- /**
- * 作者: 小超 by Administrator on 2018/8/2 12:11
- * 通用基础按钮
- */
- public class CommonButton extends AppCompatButton {
- // 文字颜色 正常 点击 无效
- private int mNormalTextColor;
- private int mPressedTextColor;
- private int mUnableTextColor;
- // 边框颜色 正常 点击 无效
- private int mNormalStrokeColor;
- private int mPressedStrokeColor;
- private int mUnableStrokeColor;
- // 背景颜色 正常 点击 无效
- private int mNormalBackgroundColor;
- private int mPressedBackgroundColor;
- private int mUnableBackgroundColor;
- // 圆角 左上 右上 左下 右下 mTopLeftRadius mTopRightRadius mBottomLeftRadius mBottomRightRadius 任何一个参数有值 mRadius 将失效
- private float mRadius;
- private float mTopLeftRadius;
- private float mTopRightRadius;
- private float mBottomLeftRadius;
- private float mBottomRightRadius;
- // 边框相关 间隔 (虚线) 宽度
- private float mStrokeDashWidth;
- private float mStrokeDashGap;
- private int mNormalStrokeWidth;
- private int mPressedStrokeWidth;
- private int mUnableStrokeWidth;
- private GradientDrawable mNormalBackground;
- private GradientDrawable mPressedBackground;
- private GradientDrawable mUnableBackground;
- private int[][] states;
- StateListDrawable mStateBackground;
- ColorStateList mTextColorStateList;
- public CommonButton(Context context) {
- this(context, null);
- }
- public CommonButton(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public CommonButton(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- initAttrs(attrs);
- initStyle();
- }
- private void initAttrs(AttributeSet attrs) {
- TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.CommonButton);
- mNormalTextColor = typedArray.getColor(R.styleable.CommonButton_normalTextColor, 0xffffffff);
- mPressedTextColor = typedArray.getColor(R.styleable.CommonButton_pressedTextColor, 0xffffffff);
- mUnableTextColor = typedArray.getColor(R.styleable.CommonButton_unableTextColor, 0xffffffff);
- mNormalBackgroundColor = typedArray.getColor(R.styleable.CommonButton_normalBackgroundColor, 0xffff5053);
- mPressedBackgroundColor = typedArray.getColor(R.styleable.CommonButton_pressedBackgroundColor, 0x80ff5053);
- mUnableBackgroundColor = typedArray.getColor(R.styleable.CommonButton_unableBackgroundColor, 0x20000000);
- mRadius = typedArray.getDimensionPixelSize(R.styleable.CommonButton_radius, 0);
- mTopLeftRadius = typedArray.getDimensionPixelSize(R.styleable.CommonButton_topLeftRadius, 0);
- mTopRightRadius = typedArray.getDimensionPixelSize(R.styleable.CommonButton_topRightRadius, 0);
- mBottomLeftRadius = typedArray.getDimensionPixelSize(R.styleable.CommonButton_bottomLeftRadius, 0);
- mBottomRightRadius = typedArray.getDimensionPixelSize(R.styleable.CommonButton_bottomRightRadius, 0);
- mStrokeDashWidth = typedArray.getDimensionPixelSize(R.styleable.CommonButton_strokeDashWidth, 0);
- mStrokeDashGap = typedArray.getDimensionPixelSize(R.styleable.CommonButton_strokeDashWidth, 0);
- mNormalStrokeWidth = typedArray.getDimensionPixelSize(R.styleable.CommonButton_normalStrokeWidth, 0);
- mPressedStrokeWidth = typedArray.getDimensionPixelSize(R.styleable.CommonButton_pressedStrokeWidth, 0);
- mUnableStrokeWidth = typedArray.getDimensionPixelSize(R.styleable.CommonButton_unableStrokeWidth, 0);
- mNormalStrokeColor = typedArray.getColor(R.styleable.CommonButton_normalStrokeColor, 0);
- mPressedStrokeColor = typedArray.getColor(R.styleable.CommonButton_pressedStrokeColor, 0);
- mUnableStrokeColor = typedArray.getColor(R.styleable.CommonButton_unableStrokeColor, 0);
- typedArray.recycle();
- }
- private void initStyle() {
- states = new int[4][];
- //pressed, focused, normal, unable
- states[0] = new int[] { Android.R.attr.state_enabled, Android.R.attr.state_pressed };
- states[1] = new int[] { Android.R.attr.state_enabled, Android.R.attr.state_focused };
- states[2] = new int[] { Android.R.attr.state_enabled };
- states[3] = new int[] { -Android.R.attr.state_enabled};
- Drawable drawable = getBackground();
- if(drawable != null && drawable instanceof StateListDrawable){
- mStateBackground = (StateListDrawable) drawable;
- }else{
- mStateBackground = new StateListDrawable();
- }
- mNormalBackground = new GradientDrawable();
- mPressedBackground = new GradientDrawable();
- mUnableBackground = new GradientDrawable();
- mNormalBackground.setColor(mNormalBackgroundColor);
- mPressedBackground.setColor(mPressedBackgroundColor);
- mUnableBackground.setColor(mUnableBackgroundColor);
- // 设置圆角
- if(mTopLeftRadius!=0||mTopRightRadius!=0||mBottomLeftRadius!=0||mBottomRightRadius!=0){
- float[] radii={
- mTopLeftRadius,mTopLeftRadius,
- mTopRightRadius,mTopRightRadius,
- mBottomRightRadius,mBottomRightRadius,
- mBottomLeftRadius,mBottomLeftRadius,};
- mNormalBackground.setCornerRadii(radii);
- mPressedBackground.setCornerRadii(radii);
- mUnableBackground.setCornerRadii(radii);
- }else{
- mNormalBackground.setCornerRadius(mRadius);
- mPressedBackground.setCornerRadius(mRadius);
- mUnableBackground.setCornerRadius(mRadius);
- }
- // 设置边框
- mNormalBackground.setStroke(mNormalStrokeWidth,mNormalStrokeColor,mStrokeDashWidth,mStrokeDashGap);
- mPressedBackground.setStroke(mPressedStrokeWidth,mPressedStrokeColor,mStrokeDashWidth,mStrokeDashGap);
- mUnableBackground.setStroke(mUnableStrokeWidth,mUnableStrokeColor,mStrokeDashWidth,mStrokeDashGap);
- // 设置字体颜色
- int[] colors = new int[] {mPressedTextColor, mPressedTextColor, mNormalTextColor, mUnableTextColor};
- mTextColorStateList = new ColorStateList(states, colors);
- setTextColor(mTextColorStateList);
- // 设置背景颜色
- mStateBackground.addState(states[0], mPressedBackground);
- mStateBackground.addState(states[1], mPressedBackground);
- mStateBackground.addState(states[3], mUnableBackground);
- mStateBackground.addState(states[2], mNormalBackground);
- setBackgroundDrawable(mStateBackground);
- }
- }
- attrs
- <!-- 通用按钮 -->
- <declare-styleable name="CommonButton">
- <!-- 文字颜色 -->
- <attr name="normalTextColor" format="color|reference" />
- <attr name="pressedTextColor" format="color|reference" />
- <attr name="unableTextColor" format="color|reference" />
- <!-- 边框相关 -->
- <attr name="strokeDashWidth" format="dimension|reference" />
- <attr name="strokeDashGap" format="dimension|reference" />
- <attr name="normalStrokeWidth" format="dimension|reference" />
- <attr name="pressedStrokeWidth" format="dimension|reference" />
- <attr name="unableStrokeWidth" format="dimension|reference" />
- <attr name="normalStrokeColor" format="color|reference" />
- <attr name="pressedStrokeColor" format="color|reference" />
- <attr name="unableStrokeColor" format="color|reference" />
- <!-- 背景颜色 -->
- <attr name="normalBackgroundColor" format="color|reference" />
- <attr name="pressedBackgroundColor" format="color|reference" />
- <attr name="unableBackgroundColor" format="color|reference" />
- <!-- 圆角 -->
- <attr name="radius" format="dimension|reference" />
- <attr name="topLeftRadius" format="dimension|reference" />
- <attr name="topRightRadius" format="dimension|reference" />
- <attr name="bottomLeftRadius" format="dimension|reference" />
- <attr name="bottomRightRadius" format="dimension|reference" />
- </declare-styleable>
来源: https://juejin.im/entry/5bc7ed7d5188255ca153ad9c