Android中设置按钮背景颜色会导致水波纹效果丢失

39

在向Android按钮添加颜色后,它失去了水波纹效果,这使得用户感觉像有一个响应点击。我该如何解决这个问题?我已经搜索了很多解决方案,但没有找到一个确定的并且不含糊的方案。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context=".ClockInOutFragment">


    <AnalogClock
        android:id="@+id/clock"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_toRightOf="@+id/date_and_time"/>


    <RelativeLayout
        android:id="@+id/date_and_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp">

        <TextView
            android:id="@+id/time_digits"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="12:10"
            android:textSize="45sp"/>

        <TextView
            android:id="@+id/am_pm"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignBaseline="@+id/time_digits"
            android:layout_toRightOf="@+id/time_digits"
            android:paddingLeft="3dp"
            android:text="PM"
            android:textSize="20sp"/>

        <TextView
            android:id="@+id/date"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/time_digits"
            android:text="Mon, July 11"
            android:textSize="22sp"/>
    </RelativeLayout>

    <!--Clock in and out buttons-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:orientation="horizontal">

        <Button
            android:id="@+id/textView3"
            android:layout_width="0dp"
            android:layout_height="56dp"
            android:layout_weight="1"
            android:background="#4CAF50"
            android:gravity="center"
            android:text="Clock In"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:textColor="#FFFFFF"/>

        <!--Divider between the clock in and out button-->
        <View
            android:layout_width="1dp"
            android:layout_height="match_parent"
            android:background="#B6B6B6"/>

        <Button
            android:id="@+id/textView4"
            android:layout_width="0dp"
            android:layout_height="56dp"
            android:layout_weight="1"
            android:background="#FF5252"
            android:gravity="center"
            android:text="Clock Out"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:textColor="#FFFFFF"/>
    </LinearLayout>


</RelativeLayout>
7个回答

54

您可以通过添加额外的涟漪drawable来添加涟漪效果和背景颜色:

您的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button_connect"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dip"
        android:fontFamily="sans-serif"
        android:text="Connect"
        android:background="@drawable/ripple"
        android:textColor="#FFFFFF"
        android:textSize="18sp" />

</LinearLayout>

ripple.xml(这是您可以在涟漪效果之外添加背景颜色的位置):

<?xml version="1.0" encoding="utf-8"?>
<!-- in drawable folder-->
<ripple
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="?android:colorControlHighlight">

    <item android:id="@android:id/mask">
        <shape android:shape="rectangle">
            <solid android:color="?android:colorAccent" />
        </shape>
    </item>

    <item>
        <shape android:shape="rectangle">
            <!-- put your background color here-->
            <solid android:color="@color/default_color" />
        </shape>
    </item>

</ripple>

1
安卓如何区分哪一个是遮罩层,哪一个是默认颜色? - Wijay Sharma
按照ID进行标识。例如 - android:id="@android:id/mask" - Edhar Khimich
这适用于更改菜单背景并保留涟漪效果。 - SagaRock101

45
这个非常简单和直接的方法是将 ?attr/selectableItemBackground 设置为您的按钮的android:foreground属性。以下xml是完全有效的并且可行的。
<Button
    android:id="@+id/btn"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@android:color/white"
    android:foreground="?attr/selectableItemBackground"/>

11
好的。不过需要注意的是,在23版本下不支持向后兼容。 - galcyurio
如何更改效果的颜色? - Mehdi Dehghani
1
这对于使用style="@style/Widget.AppCompat.Button.Colored"的曲线按钮无效。结果是阴影有尖角,而不是圆角。 - user1228891
Widget.AppCompat.Button.Borderless 配合使用效果良好。 - Konstantin Konopko

16

不要更改按钮的背景色,而是更改主题。

<style name="ButtonGray">
    <item name="colorButtonNormal">@color/gray</item>
</style>

并且在你的 XML 文件中

<Button
     android:id="@+id/accept_button"
     android:layout_height="wrap_content"
     android:layout_width="0dp"
     android:layout_weight="1"
     android:text="@string/button_accept_group"
     android:theme="@style/ButtonGray"/>

或者您可以将其添加到您的主要应用程序主题中

<style name="AppTheme"
           parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorButtonNormal">@color/primary_color</item>
</style>

而且不需要更改按钮的背景。

如果你想要完全自定义背景,你需要创建一个选择器。在那里,你可以设置涟漪效果。


11

之前没有关于MaterialButton的回答,所以我会在这里提供。

对于MaterialButton(com.google.android.material.button.MaterialButton),请使用'backgroundTint'和'rippleColor'。

<com.google.android.material.button.MaterialButton
    android:id="@+id/button_sign_in"
    android:layout_width="0dp"
    android:layout_height="55dp"
    app:backgroundTint="@android:color/white"
    app:rippleColor="?attr/colorControlHighlight"

?attr/colorControlHighlight 是默认的波纹颜色,你可以改变这个值。


8

只需使用:

android:backgroundTint="#4CAF50"

改为:

android:background="#4CAF50"

不要忘记将你的Button更改为android.support.v7.widget.AppCompatButton


2
这不适用于 androidx.appcompat.widget.AppCompatButton - Konstantin Konopko

1
实际上,您可以使用drawable的<layer-list>将涟漪效果与任何其他drawable组合。这也是适用于pre-lolipop的通用解决方案:我已在许多配置中进行了测试。
唯一的问题是,在<layer-list>内部出现?selectableItemBackground时,pre-lolipop会崩溃,因此我们必须以编程方式创建LayerDrawable。
一个非常快速简单的解决方案如下:
为您的View指定
android:background="?selectableItemBackground"

然后在代码的任何位置创建mySpecialDrawable并使用以下技巧:

Drawable[] layers = {mySpecialDrawable, getBackground()};
setBackgroundDrawable(new LayerDrawable(layers).mutate()); 

请注意,.mutate()对于LayeredDrawable至关重要!
当您已经拥有自定义视图并且更喜欢扩展其功能和兼容性而不是添加额外的空FrameLayout作为父级时,更复杂的解决方案可能会很有用。
在attrs.xml中放置以下内容:
<resources>
    <declare-styleable name="MyView">
        <attr name="selectableBackground" format="reference"/>
        <attr name="backgroundDrawable" format="reference"/>
    </declare-styleable>
</resources>

然后在您的View子类内部:

private Drawable selectableBackground;
private Drawable backgroundDrawable;

public MyView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    try {
        TypedArray attributeArray;
        attributeArray = context.obtainStyledAttributes(attrs, R.styleable.MyView);

        int id = attributeArray.getResourceId(R.styleable.MyView_selectableBackground, -1);
        if (id != -1) {
            selectableBackground = ResourcesCompat.getDrawable(getResources(), id, context.getTheme());
        }
        id = attributeArray.getResourceId(R.styleable.MyView_backgroundDrawable, -1);
        if (id != -1) {
            backgroundDrawable = ResourcesCompat.getDrawable(getResources(), id, context.getTheme());
        }

        constructBackground();
        attributeArray.recycle();
    } catch (Exception e) {
        Log.e(this.toString(), "Attributes initialization error", e);
        throw e;
    }
}

void setSelectableBackground(Drawable drawable) {
    selectableBackground = drawable;
    constructBackground();
}

void setDrawable(Drawable drawable) {
    backgroundDrawable = drawable;
    constructBackground();
}

private void constructBackground() {
    if (selectableBackground != null) {
        if (backgroundDrawable != null) {
            Drawable[] layers = {backgroundDrawable, selectableBackground};
            setBackgroundDrawable(new LayerDrawable(layers).mutate());      // Both, using layers
        } else setBackgroundDrawable(selectableBackground);                 // Selectable only
    } else setBackgroundDrawable(backgroundDrawable);                       // Background only or null
}

我更喜欢这种方法,因为它没有像android:foreground属性那样的问题,该属性是23+或在FrameLayout中包含可点击视图时会带来额外的开销。

-1

你应该使用样式

<style parent="Theme.AppCompat.Light" name="RaisedButtonGreen">
    <item name="colorButtonNormal">@color/green</item>
    <item name="colorControlHighlight">@color/greenLight</item>
    <item name="android:textColor">@android:color/white</item>
</style>

这是最优解决方案

<Button
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:text="Button with ripple for style"
    android:theme="@style/RaisedButtonGreen"/>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接