Android-自定义反色圆角Button

这篇博客介绍了如何在Android中自定义反色圆角Button,通过使用<shape>和<selector>标签创建XML文件来设置按钮样式,同时讲解了如何用代码实现相同效果,使用StateListDrawable和ColorStateList。还详细阐述了如何利用attrs.xml文件定义自定义属性,以方便在不同场景下灵活应用反色效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


学习目标:

                掌握使用 <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"
     />





另外给大家分享一个常用颜色值;







      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值