学习目标:
掌握使用 <shape> 标签和 <selector> 标签 在 Button 视图上的使用。
掌握使用代码代替xml文件的功能,实现同上效果。
掌握自定义属性的使用。
写一个自定义Button配合自定义属性,完成反色效果。
1.> <shape> 标签 与 <selector> 标签
在 drawable 文件夹下新建一个button_shape.xml文件,来对 shape 进行描述
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- 圆角半径,越大,则角越圆,越小则角越方 -->
<corners android:radius="5dp"/>
<!-- 描边线 -->
<stroke android:width="5dp" android:color="#6699FF"/>
<!-- 填充 -->
<solid android:color="#6699FF"/>
</shape>
写完之后,便可以在布局文件中,使用 backgroud 来引用这个 shape了
<Button
android:text="普通按钮"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#ffffff"
<strong>android:background="@drawable/button_shape"</strong>/>
效果如图所示,非常简单
因为Button是可点击的,每一次对 Button进行触碰的时候,都会改变它的状态。
我们可以通过为 Button 的 backgroud 指定一个 处理方案<selector>,来告诉 Button,对于哪一样的状态,用什么用的背景图
drawable >> while_button.xml
<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/white_radius_clicking_button"/>
<item android:state_pressed="false" android:drawable="@drawable/white_radius_button"/>
<!-- 默认时的背景图片-->
<item android:drawable="@drawable/white_radius_button" />
</selector>
针对于反色,我们设定在默认状体下,Button的形状为:蓝色描边线,白底填充,蓝色字体.
drawable >> white_radius_button.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<stroke android:width="1dp" android:color="#6699FF"/>
<corners android:radius="5dp"/>
<solid android:color="@android:color/white"/>
</shape>
当我们点击的时候,修改对应的状态为: 蓝色描边线,蓝色填充,白色字体.
drawable >> white_radius_clicking_button.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<corners android:radius="5dp"/>
<solid android:color="#6699FF"/>
<stroke android:width="1dp" android:color="#6699FF"/>
</shape>
当然,如上只是设置了Button的形状,但是对于 Button中文字的颜色也需要进行配置.
drawable >> white_font.xml
<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="#ffffff"/>
<item android:state_pressed="false" android:color="#6699FF"/>
<item android:color="#6699FF" />
</selector>
OK,为Button添加backgroud,以及textcolor
<Button android:text="蓝白反色按钮"
android:layout_width="match_parent"
android:layout_height="wrap_content"
<strong>android:textColor="@drawable/white_font"
android:background="@drawable/while_button"</strong>/>
效果如图所示:
2.> StateListDrawable 和 ColorStateList
同样的效果,可以使用代码来实现。
可以使用 GradientDrawable 来代替 Shape.
创建一个继承Button的视图,并在其构造函数中编码:
// 相当于创建了 shape
GradientDrawable gd = new GradientDrawable();
// 设置 shape 的填充色
gd.setColor(Color.BLACK);
// 设置 shape 的圆角
gd.setCornerRadius(10);
// 设置 shape 的描边线的宽度和颜色
gd.setStroke(1, Color.BLACK);
setBackground(gd);
同样的,使用 StateListDrawable 来代替使用xml来配置 Button在不同状态下的背景图
StateListDrawable statelistDrawable = new StateListDrawable();
int pressed = android.R.attr.state_pressed;
int windowfocused = android.R.attr.state_window_focused;
// -pressed 相当于 false
statelistDrawable.addState(new int[] { pressed, windowfocused },drable0);
statelistDrawable.addState(new int[] { -pressed,windowfocused },drable1);
<pre name="code" class="java">setBackground(statelistDrawable);
了解了这个类的相关使用,就可以在代码中同样实现反色效果了。
// 定义一个默认填充色
int inverseColor = Color.BLACK;
// 统一的圆角半径
int roundRadius = 10;
// 统一的描边线的宽度
int strokeWidth = 1;
// 描边线的颜色
int strokeColor = inverseColor;
/* 先设定默认情况下的形状 */
// 默认状态下的填充色为白色
int defaultFillColor = Color.parseColor("#ffffff");
GradientDrawable defaultGd = new GradientDrawable();
defaultGd.setColor(defaultFillColor);
defaultGd.setCornerRadius(roundRadius);
defaultGd.setStroke(strokeWidth, strokeColor);
/* 再设定按下情况下的形状 */
// 设置反色为我们定义的颜色
int pressedFillColor = inverseColor;
GradientDrawable pressedGd = new GradientDrawable();
pressedGd.setColor(pressedFillColor);
pressedGd.setCornerRadius(roundRadius);
pressedGd.setStroke(strokeWidth, strokeColor);
StateListDrawable statelistDrawable = new StateListDrawable();
int pressed = android.R.attr.state_pressed;
int windowfocused = android.R.attr.state_window_focused;
// 分别为不同的状态装配不同的背景
// "-"号表示该状态值为false .即不匹配
statelistDrawable.addState(new int[] { pressed, windowfocused },pressedGd);
statelistDrawable.addState(new int[] { -pressed,windowfocused },defaultGd);
setBackground(statelistDrawable);
// <span style="font-size:18px;"><strong>另外还需要设置一下字体的颜色的反色效果</strong></span>
int[] unpress = new int[]{-pressed,windowfocused};
int[] btnPressed = new int[]{pressed, windowfocused};
int[][] states = new int[][]{unpress,btnPressed };
int[] colors = new int[]{inverseColor,Color.parseColor("#ffffff")};
ColorStateList colorStateList = new ColorStateList(states, colors);
this.setTextColor(colorStateList);
再布局文件中加入我们自定义的这个Button,可以看到效果:
3.> attrs.xml 文件的使用
很明显,我们不可能为了不同的颜色效果专门写xml文件,或者重新自定义Button.这样我们就需要在使用我们自定义Button的时候,
为其传入我们想要的反色。然后再构建函数中获取我们传入的值,然后再将其作用到Button上.
这样我们就需要自定义属性来帮帮忙了.
第一步. values>>attrs.xml 定义我们想要的属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 属性集的名 -->
<declare-styleable name="inverseColBtn">
<!-- 属性名 , 及属性值的格式 -->
<attr name="inverseColor" format="color"/>
<attr name="whiteFillFirst" format="boolean" />
</declare-styleable>
</resources>
第二步,在布局文件中,让视图使用这个属性
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:myStyle="http://schemas.android.com/apk/res/com.example.buttons"
android:layout_width="match_parent"
android:layout_height="match_parent"
.......>
<zy.pointer.custom.InverseColButton android:text="InversColBtn"
myStyle:inverseColor="@android:color/black"
myStyle:whiteFillFirst="false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
首先是申明一个别名
xmlns:myStyle="http://schemas.android.com/apk/res/com.example.buttons"
myStyle 就是这个别名,它将在后面使用,可以随便写
http://schemas.android.com/apk/res/com.example.buttons
这一部分呢,前面的照写,后面的那一段就是我们工程的包名
再然后就是再我们自定义的组件上写我们的自定义属性了。
myStyle:inverseColor="@android:color/black"
myStyle:whiteFillFirst="false"
myStyle就是我们申明的别名了,后面的属性名就不要乱写了。是 attrs.xml 中定义的属性集中的属性名
第三步,获取我们的自定义属性的值。
public InverseColButton(Context context, AttributeSet attrs) {
super(context, attrs);
//TypedArray是一个数组容器
//先让属性集的名字
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.inverseColBtn);
//防止在XML文件里没有定义,就加上了默认值
//再放属性集里面定义的属性名
int inverseColor = a.getColor(R.styleable.inverseColBtn_inverseColor, Color.BLACK);
boolean whiteFillFirst = a.getBoolean(R.styleable.inverseColBtn_whiteFillFirst, true);
.......
4.> InverseColButton
我们定义了两个特别的属性:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 属性集的名 -->
<declare-styleable name="inverseColBtn">
<!-- 属性名 , 及属性值的格式 -->
<attr name="inverseColor" format="color"/>
<attr name="whiteFillFirst" format="boolean" />
</declare-styleable>
</resources>
其中 inverseColor 是我们希望的反色效果使用的颜色
whiteFillFirst 是说是否使用白色首先作为填充色。这个值的作用,我放在这里的期望是,将反色效果倒置一下.
直接上 InverseColButton 的代码吧。
public class InverseColButton extends Button{
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public InverseColButton(Context context, AttributeSet attrs) {
super(context, attrs);
//TypedArray是一个数组容器
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.inverseColBtn);
//防止在XML文件里没有定义,就加上了默认值,默认反色使用黑色,默认首先使用白色进行填充.
int inverseColor = a.getColor(R.styleable.inverseColBtn_inverseColor, Color.BLACK);
boolean whiteFillFirst = a.getBoolean(R.styleable.inverseColBtn_whiteFillFirst, true);
// 统一的圆角半径
int roundRadius = 10;
// 统一的描边线的宽度
int strokeWidth = 1;
// 描边线的颜色
int strokeColor = inverseColor;
/* 先设定默认情况下的形状 */
// 默认状态下的填充色
int defaultFillColor = Color.WHITE;
GradientDrawable whiteFillGd = new GradientDrawable();
whiteFillGd.setColor(defaultFillColor);
whiteFillGd.setCornerRadius(roundRadius);
whiteFillGd.setStroke(strokeWidth, strokeColor);
/* 再设定按下情况下的形状 */
int pressedFillColor = inverseColor;
GradientDrawable inverseGd = new GradientDrawable();
inverseGd.setColor(pressedFillColor);
inverseGd.setCornerRadius(roundRadius);
inverseGd.setStroke(strokeWidth, strokeColor);
StateListDrawable statelistDrawable = new StateListDrawable();
int pressed = android.R.attr.state_pressed;
int windowfocused = android.R.attr.state_window_focused;
// 如果使用白色首先填充,则和以前一样
if(whiteFillFirst){
statelistDrawable.addState(new int[] { pressed, windowfocused },inverseGd);
statelistDrawable.addState(new int[] { -pressed,windowfocused },whiteFillGd);
}else{
// 否则就是反着的效果
statelistDrawable.addState(new int[] { pressed, windowfocused },whiteFillGd);
statelistDrawable.addState(new int[] { -pressed,windowfocused },inverseGd);
}
setBackground(statelistDrawable);
// 另外还需要设置一下字体的颜色的反色效果
int[] unpress = new int[]{-pressed,windowfocused};
int[] pressing = new int[]{pressed, windowfocused};
int[][] states = new int[][]{unpress,pressing};
int[] colors;
// 同样的,字体的颜色要和上面的一致.
if(whiteFillFirst){
colors = new int[]{inverseColor,Color.WHITE};
}else{
colors = new int[]{Color.WHITE,inverseColor};
}
ColorStateList colorStateList = new ColorStateList(states, colors);
this.setTextColor(colorStateList);
}
}
添加Button,让它们显示一下相反的效果给大伙看看
<zy.pointer.custom.InverseColButton android:text="InversColBtn - true"
myStyle:inverseColor="#800080"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<zy.pointer.custom.InverseColButton android:text="InversColBtn - false"
myStyle:inverseColor="#800080"
<strong>myStyle:whiteFillFirst="false"</strong>
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
另外给大家分享一个常用颜色值;