Hiệu ứng vật liệu trên nút với màu nền


246

Tôi đang sử dụng thư viện hỗ trợ Android v21.

Tôi đã tạo một nút với màu nền tùy chỉnh. Các hiệu ứng thiết kế Vật liệu như gợn, lộ đã biến mất (ngoại trừ độ cao khi nhấp) khi tôi sử dụng màu nền.

 <Button
 style="?android:attr/buttonStyleSmall"
 android:background="?attr/colorPrimary"
 android:textColor="@color/white"
 android:textAllCaps="true"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="Button1"
 />

Lý lịch Sau đây là một nút bình thường và các hiệu ứng đang hoạt động tốt.

<Button
 style="?android:attr/buttonStyleSmall"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:textAllCaps="true"
 android:text="Button1"
/>

Nút mặc định


9
Điều này xảy ra bởi vì bạn thay thế nền bằng tất cả các hiệu ứng Vật liệu đẹp bằng một màu đơn sắc. Về cách bạn tô màu đúng cho một nút trong khi vẫn giữ các hiệu ứng Vật liệu, không ai trên SO có thể tìm ra điều đó.
Nathan Walters

2
@SweetWisher Ripple và các hiệu ứng khác không được áp dụng trong nút khi tôi thay đổi màu nền.
Sathesh

1
@NathanWalters Nhưng màu xám mặc định là xấu. :-(
Sathesh

6
Hãy tin tôi, tôi biết ... Chúng ta sẽ mắc nợ lớn cho bất cứ ai tìm ra cách làm điều này đúng.
Nathan Walters

1
Câu trả lời tuyệt vời stackoverflow.com/a/32238361/1318946
Pratik Butani

Câu trả lời:


431

Khi bạn sử dụng android:background, bạn đang thay thế phần lớn kiểu dáng và giao diện của một nút bằng một màu trống.

Cập nhật: Kể từ phiên bản 23.0.0 của AppCompat , có một Widget.AppCompat.Button.Coloredkiểu mới sử dụng chủ đề của bạn colorButtonNormalcho màu bị tắt và colorAccentcho màu được bật.

Điều này cho phép bạn áp dụng nó vào nút của bạn trực tiếp thông qua

<Button
  ...
  style="@style/Widget.AppCompat.Button.Colored" />

Nếu bạn cần một tùy chỉnh colorButtonNormalhoặc colorAccent, bạn có thể sử dụng một ThemeOverlaynhư được giải thích trong pro-tip nàyandroid:themetrên nút.

Trả lời trước

Bạn có thể sử dụng drawable trong thư mục v21 cho nền của mình, chẳng hạn như:

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

Điều này sẽ đảm bảo màu nền của bạn là ?attr/colorPrimaryvà có hoạt ảnh gợn mặc định bằng cách sử dụng mặc định ?attr/colorControlHighlight(mà bạn cũng có thể đặt trong chủ đề của mình nếu bạn muốn).

Lưu ý: bạn sẽ phải tạo một bộ chọn tùy chỉnh ít hơn v21:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/primaryPressed" android:state_pressed="true"/>
    <item android:drawable="@color/primaryFocused" android:state_focused="true"/>
    <item android:drawable="@color/primary"/>
</selector>

Giả sử bạn có một số màu bạn muốn cho trạng thái mặc định, được nhấn và tập trung. Cá nhân, tôi đã chụp ảnh màn hình của một gợn sóng giữa chừng được chọn và kéo trạng thái chính / tập trung ra khỏi đó.


13
Câu trả lời tốt đẹp! Chính xác những gì tôi đang tìm kiếm, tuy nhiên cần phải làm sạch và xây dựng lại trước khi dự án quyết định xác định drawable trong drawable-v21.
dùng1354603


4
@ianhanniballake Tôi tự hỏi làm thế nào để kết hợp kỹ thuật làm việc này mà không mất tùy chỉnh góc tròn trong các nút đó
Joaquin Iurchuk

3
@ianhanniballake chỉ là một nhận xét, có thể vẽ trong Ripple trong <item android: drawable ... /> không thể là một màu trong suốt. Trong trường hợp đó, Ripple sẽ không được hiển thị. Phải mất một thời gian tôi mới nhận ra điều đó.
Ivan Kušt

2
Với appcompat 23.1.1 và API 22, cả hai trạng thái bị vô hiệu hóa và kích hoạt đều lấy màu sắc của chủ đề.
Rémy DAVID

93

Có một giải pháp đơn giản khác để cung cấp nền tùy chỉnh cho các nút "Flat" trong khi vẫn giữ hiệu ứng "Chất liệu" của chúng.

  1. Đặt nút của bạn trong Viewgroup với nền được đặt ở đó
  2. đặt selectableItemBackground từ chủ đề hiện tại làm nền cho nút của bạn (API> = 11)

I E :

<FrameLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@color/blue">
    <Button
        style="?android:attr/buttonStyleSmall"
        android:background="?android:attr/selectableItemBackground"
        android:textColor="@android:color/white"
        android:textAllCaps="true"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Button1"
        />
</FrameLayout>

Có thể được sử dụng cho căn hộ nút , nó hoạt động trên API> = 11 và bạn sẽ có hiệu ứng gợn trên các thiết bị> = 21, giữ các nút thông thường trên trước 21 cho đến khi AppCompat được cập nhật để hỗ trợ Ripple ở đó.

Bạn cũng có thể sử dụng selectableItemBackgroundBorderless chỉ với> = 21 nút.


Bạn thực sự nghĩ ra khỏi hộp :-) Mặc dù đây là một cách để làm điều này, nhưng nó có thể làm tăng việc ghép mã và sử dụng các kiểu sẽ là cách được khuyến nghị.
Sathesh

3
Điều này tạo ra một nút phẳng với nền màu, vâng. Nhưng nút được tạo trông giống như một hình vuông, không có góc tròn và hiệu ứng bóng.
Sanket Berde

7
@SanketBerde Chính xác. Vì đó là nút "phẳng".
kiruwka

2
Các câu hỏi ban đầu không đề cập đến căn hộ. btw, nếu bạn có cha mẹ <CardView> trong giải pháp của mình thay vì <FrameLayout>, nút kết quả sẽ được nâng lên và có bóng. Điều này thậm chí hoạt động trong các phiên bản tiền kẹo.
Sanket Berde

1
@SanketBerde thật tuyệt khi biết về CardViewcách tiếp cận, cảm ơn vì đã chia sẻ!
kiruwka

88

Dưới đây là một cách tương thích đơn giản và lạc hậu để cung cấp hiệu ứng gợn cho các nút được nâng lên với nền tùy chỉnh.

Bố cục của bạn sẽ trông như thế này

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/my_custom_background"
    android:foreground="?android:attr/selectableItemBackground"/>

9
Đây là cách dễ nhất không phiền phức để thực hiện điều này. Câu trả lời tốt.
Tyler Pfaff

1
api 21+ nhưng không hoạt động. Áp dụng trên bố cục tuyến tính với nhấp chuột-đúng, nền - màu khác nhau, được chỉ định trước.
Alex

3
Vì Nút là TextView và không phải là FrameLayout, foregroundkhông có hiệu lực trước 23. google.com/
Kẻ

2
ĐẸP! Tôi thậm chí không biết "tiền cảnh" là một thứ!
Eric Schlenz

2
Hoạt động như một lá bùa ..!
Kannan

25

Tôi gặp vấn đề này ngày hôm nay thực sự chơi với thư viện v22.

Giả sử rằng bạn đang sử dụng các kiểu bạn có thể đặt thuộc colorButtonNormaltính và các nút sẽ sử dụng màu đó theo mặc định.

<style name="AppTheme" parent="BaseTheme">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/primaryColor</item>
    <item name="colorPrimaryDark">@color/primaryColorDark</item>
    <item name="colorAccent">@color/accentColor</item>
    <item name="colorButtonNormal">@color/primaryColor</item>
</style>

Ngoài ra, bạn vẫn có thể tạo kiểu cho nút sau đó sử dụng mỗi nút đó nếu bạn cần một loại màu sắc (chưa được thử nghiệm, chỉ là suy đoán).

Nhớ thêm android:trước tên vật phẩm theo kiểu v21 của bạn .


Để biết các loại nút màu, hãy xem câu trả lời khác của Robert: stackoverflow.com/a/31825439/1617737
ban-geengineering

Với màu nền hiện được đặt, đó cũng là một thuộc tính chung mà tôi có thể sử dụng trong khối mã ở trên để chỉ định màu văn bản nút?
ban-geengineering

24

Với AppCompat (22.1.1+), bạn có thể thêm một kiểu như thế này:

<style name="MyGreenButton">
    <item name="colorButtonNormal">#009900</item>
</style>

Và sử dụng nó bằng cách chỉ áp dụng phong cách:

<android.support.v7.widget.AppCompatButton
    style="@style/MyGreenButton"
    android:layout_width="match_width"
    android:layout_height="wrap_content"
    android:text="A Green Button"
    />

Thay đổi màu sắc theo lập trình, tôi thấy rằng cách duy nhất để cập nhật màu (trên API 15 hoặc 16) là sử dụng 'danh sách màu nền' thay thế. Và nó không xóa hoạt hình xuyên tâm đẹp mắt trên các thiết bị API 21:

ColorStateList colorStateList = new ColorStateList(new int[][] {{0}}, new int[] {0xFF009900}); // 0xAARRGGBB
button.setSupportBackgroundTintList(colorStateList);

Bởi vì button.setBackground(...)button.getBackground().mutate().setColorFilter(...)không thay đổi màu nút trên API 15 và 16 giống như trên API 21.


1
Cảm ơn bạn rất nhiều, nó hoạt động hoàn hảo với tôi (ngay cả khi sử dụng Nút trong bố cục xml khi ứng dụng thay thế AppCompat thay thế nó bằng AppCompatButton)
Louis CAD

1
Sử dụng ColorStateList.valueOf( ... )để xây dựng một đơn giản ColorStateListchỉ có một màu.
Taig

colorAccent và rippleColor không hoạt động theo phong cách
Yar

Cám ơn vì bài viết. Điều gì làm việc cho tôi: ViewCompat.setBackgroundTintList(myButton, ColorStateList.valueOf(myColor); Javadoc setSupportBackgroundTintListnói rằng nó nên được gọi theo cách này.
JerabekJakub

22

Câu trả lời của @ ianhanniballake hoàn toàn chính xác và đơn giản. Nhưng tôi phải mất vài ngày để hiểu. Đối với một người không hiểu câu trả lời của mình, đây là chi tiết thực hiện

<Button
        android:id="@+id/btn"
        style="@style/MaterialButton"
        ... />


<style name="MaterialButton" parent="Widget.AppCompat.Button.Colored">
    <item name="android:theme">@style/Theme.MaterialButton</item>
   ...
</style>


<style name="Theme.MaterialButton" parent="YourTheme">
    <item name="colorAccent">@color/yourAccentColor</item>
    <item name="colorButtonNormal">@color/yourButtonNormalColor</item>
</style>

=== Hoặc ===

<Button
        android:id="@+id/btn"
        style="@style/Widget.AppCompat.Button.Colored"
        android:theme="@style/Theme.MaterialButton" />

<style name="Theme.MaterialButton" parent="YourTheme">
    <item name="colorAccent">@color/yourAccentColor</item>
    <item name="colorButtonNormal">@color/yourButtonNormalColor</item>
</style>

5
Câu trả lời của bạn là mảnh ghép cuối cùng cho tôi. Người ta cũng có thể viết colorButtonNormaltrong chủ đề cơ bản @style/AppTheme. Điều này cung cấp một màu mặc định cho AppCompat để tô màu các nút tương ứng. Và sau đó có thể sử dụng câu trả lời của bạn để tạo chủ đề cho một khung nhìn riêng lẻ.
Siddharth Pant

1
Là nó android:theme="Theme.MaterialButton"hayandroid:theme="@style/Theme.MaterialButton"
osrl

1
@osrl Đó là android:theme="@style/Theme.MaterialButton". Cảm ơn bạn đã chính xác.
Frank Nguyễn

12

Tôi đã sử dụng nềnTint và foreground:

<Button
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:backgroundTint="@color/colorAccent"
    android:foreground="?android:attr/selectableItemBackground"
    android:textColor="@android:color/white"
    android:textSize="10sp"/>

afaik không cần thiết cho thuộc tính tiền cảnh vì nềnTint không ghi đè lên gợn tiêu chuẩn
Julian Os

7

Tôi đã đến bài viết này để tìm cách để có một màu nền của ListViewMục của tôi , nhưng vẫn giữ được gợn.

Tôi chỉ cần thêm màu của mình làm nền và selectableItemBackground làm nền trước:

<style name="my_list_item">
    <item name="android:background">@color/white</item>
    <item name="android:foreground">?attr/selectableItemBackground</item>
    <item name="android:layout_height">@dimen/my_list_item_height</item>
</style>

và nó hoạt động như một lá bùa. Tôi đoán kỹ thuật tương tự cũng có thể được sử dụng cho các nút. Chúc may mắn :)



6

Nếu bạn quan tâm đến ImageButton, bạn có thể thử điều đơn giản này:

<ImageButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@android:drawable/ic_button"
    android:background="?attr/selectableItemBackgroundBorderless"
/>

5

v22.1của appcompat-v7giới thiệu một số khả năng mới. Bây giờ có thể chỉ định một chủ đề cụ thể cho một chế độ xem.

Không sử dụng ứng dụng: chủ đề để tạo kiểu Thanh công cụ. Giờ đây, bạn có thể sử dụng android: theme cho thanh công cụ trên tất cả các thiết bị API cấp 7 trở lên và android: hỗ trợ chủ đề cho tất cả các tiện ích trên API cấp 11 trở lên.

Vì vậy, thay vì đặt màu mong muốn trong một chủ đề toàn cầu, chúng tôi tạo một màu mới và chỉ gán nó cho Button

Thí dụ:

<style name="MyColorButton" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorButtonNormal">@color/myColor</item>
</style>

Và sử dụng phong cách này làm chủ đề của bạn Button

<Button
 style="?android:attr/buttonStyleSmall"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="Button1"
 android:theme="@style/MyColorButton"/>

4

Nếu bạn ổn với việc sử dụng thư viện của bên thứ ba, hãy xem traex / RippleEffect . Nó cho phép bạn thêm hiệu ứng Ripple vào BẤT K view chế độ xem nào chỉ bằng một vài dòng mã. Bạn chỉ cần bọc, trong tệp bố cục xml của bạn, phần tử bạn muốn có hiệu ứng gợn với một com.andexert.library.RippleViewthùng chứa.

Là một phần thưởng bổ sung, nó yêu cầu Min SDK 9 để bạn có thể có sự thống nhất về thiết kế trên các phiên bản HĐH.

Dưới đây là một ví dụ được lấy từ repo GitHub của thư viện:

<com.andexert.library.RippleView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:rv_centered="true">

    <ImageView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@android:drawable/ic_menu_edit"
        android:background="@android:color/holo_blue_dark"/> 

</com.andexert.library.RippleView>

Bạn có thể thay đổi màu gợn bằng cách thêm thuộc tính này vào phần tử RippleView: app:rv_color="@color/my_fancy_ripple_color


3
<android.support.v7.widget.AppCompatButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:backgroundTint="#fff"
    android:textColor="#000"
    android:text="test"/>

Sử dụng

xmlns:app="http://schemas.android.com/apk/res-auto"

và màu sắc sẽ được chấp nhận trên pre-lolipop


2

Có hai cách tiếp cận được giải thích trong hướng dẫn tuyệt vời là Alex Lockwood: http://www.androiddesignpotypes.com/2016/08/coloring-buttons-with-themeoverlays-background-tints.html :

Cách tiếp cận # 1: Sửa đổi màu nền của nút w / ThemeOverlay

<!-- res/values/themes.xml -->
<style name="RedButtonLightTheme" parent="ThemeOverlay.AppCompat.Light">
    <item name="colorAccent">@color/googred500</item>
</style>

<Button
    style="@style/Widget.AppCompat.Button.Colored"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:theme="@style/RedButtonLightTheme"/>

Cách tiếp cận # 2: Đặt màu nền của AppCompatButton

<!-- res/color/btn_colored_background_tint.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Disabled state. -->
    <item android:state_enabled="false"
          android:color="?attr/colorButtonNormal"
          android:alpha="?android:attr/disabledAlpha"/>

    <!-- Enabled state. -->
    <item android:color="?attr/colorAccent"/>

</selector>

<android.support.v7.widget.AppCompatButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:backgroundTint="@color/btn_colored_background_tint"/>

2

Lập trình áp dụng màu sắc:

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {

    ColorStateList colorStateListRipple = new ColorStateList(
            new int[][] {{0}},
            new int[] {Color.WHITE} // ripple color
            );

    RippleDrawable rippleDrawable = (RippleDrawable) myButton.getBackground();
    rippleDrawable.setColor(colorStateListRipple);
    myButton.setBackground(rippleDrawable); // applying the ripple color
}

ColorStateList colorStateList = new ColorStateList(
        new int[][]{
                new int[]{android.R.attr.state_pressed}, // when pressed
                new int[]{android.R.attr.state_enabled}, // normal state color
                new int[]{} // normal state color
        },
        new int[]{
                Color.CYAN, // when pressed
                Color.RED, // normal state color
                Color.RED // normal state color
        }
);

ViewCompat.setBackgroundTintList(myButton, colorStateList); // applying the state colors

-1

Tôi đã thử điều này:

android:backgroundTint:"@color/mycolor"

thay vì thay đổi thuộc tính nền. Điều này không loại bỏ hiệu ứng vật liệu.


Điều này sẽ không hoạt động cho các thiết bị tiền Lollipop (chiếm 70% thị phần). Trên thực tế, nó đã được nhập vào nhưng Android Studio cho đến nay vẫn hiển thị lỗi khi sử dụng mà không có tiền tố Android.
Siddharth Pant
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.