Materialeffekt auf Knopf mit Hintergrundfarbe

245

Ich verwende die Android v21-Unterstützungsbibliothek.

Ich habe eine Schaltfläche mit benutzerdefinierter Hintergrundfarbe erstellt. Die Materialdesign-Effekte wie Welligkeit und Enthüllung sind verschwunden (mit Ausnahme der Höhe beim Klicken), wenn ich die Hintergrundfarbe verwende.

 <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"
 />

Hintergrund Das Folgende ist eine normale Schaltfläche und die Effekte funktionieren einwandfrei.

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

Standardschaltfläche

Sathesh
quelle
9
Dies liegt daran, dass Sie den Hintergrund durch alle schönen Materialeffekte durch eine Volltonfarbe ersetzen. Wie Sie eine Schaltfläche richtig einfärben und dabei die Materialeffekte beibehalten, konnte bisher noch niemand auf SO herausfinden.
Nathan Walters
2
@SweetWisher Die Welligkeit und andere Effekte werden nicht auf die Schaltfläche angewendet, wenn ich die Hintergrundfarbe ändere.
Sathesh
1
@ NathanWalters Aber die graue Standardfarbe ist hässlich. :-(
Sathesh
6
Glauben Sie mir, ich weiß ... Wir werden jedem, der herausfindet, wie man das richtig macht, große Schulden machen.
Nathan Walters
1
Fantastische Antwort stackoverflow.com/a/32238489/1318946
Pratik Butani

Antworten:

431

Wenn Sie verwenden android:background, ersetzen Sie einen Großteil des Stils und des Erscheinungsbilds einer Schaltfläche durch eine leere Farbe.

Update: Ab Version 23.0.0 von AppCompat gibt es einen neuen Widget.AppCompat.Button.ColoredStil, der Ihre DesignscolorButtonNormal für die deaktivierte Farbe und colorAccentfür die aktivierte Farbe verwendet.

Auf diese Weise können Sie es direkt über auf Ihre Schaltfläche anwenden

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

Wenn Sie ein benutzerdefiniertes colorButtonNormaloder benötigen colorAccent, können Sie ein verwenden, ThemeOverlaywie in erläutert diesem Pro-Tipp und android:themeauf der Schaltfläche .

Vorherige Antwort

Sie können ein Drawable in Ihrem v21-Verzeichnis für Ihren Hintergrund verwenden, z.

<?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>

Dadurch wird sichergestellt, dass Ihre Hintergrundfarbe ist ?attr/colorPrimary die Standard-Ripple-Animation verwendet und verwendet, wobei die Standardeinstellung verwendet wird ?attr/colorControlHighlight(die Sie auch in Ihrem Design festlegen können, wenn Sie möchten).

Hinweis: Sie müssen einen benutzerdefinierten Selektor für weniger als v21 erstellen:

<?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>

Angenommen, Sie haben einige Farben, die Sie für den Standard-, Druck- und Fokusstatus möchten. Persönlich habe ich einen Screenshot einer Welligkeit auf halbem Weg durch die Auswahl gemacht und den primären / fokussierten Zustand daraus gezogen.

ianhanniballake
quelle
13
Gute Antwort! Genau das, wonach ich gesucht habe, musste jedoch gereinigt und neu erstellt werden, bevor das Projekt beschloss, das Drawable in drawable-v21 zu identifizieren.
user1354603
4
@ianhanniballake Ich frage mich, wie man diese Arbeitstechnik kombiniert, ohne die Anpassung abgerundeter Ecken in dieser Schaltfläche zu verlieren
Joaquin Iurchuk
3
@ianhanniballake nur ein Kommentar, der in Welligkeit unter <item android: drawable ... /> gezeichnet werden kann, kann keine transparente Farbe sein. In diesem Fall wird keine Welligkeit angezeigt. Ich habe eine Weile gebraucht, um das zu realisieren.
Ivan Kušt
2
Mit Appcompat 23.1.1 und API 22 nehmen sowohl der deaktivierte als auch der aktivierte Status die Farbe colorButtonNormal des Themas an.
Rémy DAVID
93

Es gibt eine weitere einfache Lösung, um benutzerdefinierte Hintergründe für "Flat" -Schaltflächen bereitzustellen und gleichzeitig deren "Material" -Effekte beizubehalten.

  1. Platzieren Sie Ihre Schaltfläche in ViewGroup mit dem gewünschten Hintergrund
  2. Legen Sie selectableItemBackground aus dem aktuellen Thema als Hintergrund für Ihre Schaltfläche fest (API> = 11).

dh:

<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>

Kann für Flat verwendet werden Schaltflächen verwendet werden, funktioniert unter API> = 11, und Sie erhalten Ripple-Effekte auf> = 21 Geräten, wobei die regulären Schaltflächen auf Pre-21 bleiben, bis AppCompat aktualisiert wird, um auch dort Ripple zu unterstützen.

Sie können selectableItemBackgroundBorderless auch nur für> = 21 Schaltflächen verwenden.

kiruwka
quelle
Sie haben buchstäblich über den Tellerrand hinaus gedacht :-) Obwohl dies eine Möglichkeit ist, könnte dies die Codekopplung erhöhen und die Verwendung von Stilen wäre die empfohlene Methode.
Sathesh
3
Dadurch wird eine flache Schaltfläche mit farbigem Hintergrund erstellt, ja. Die erstellte Schaltfläche sieht jedoch wie ein Quadrat aus, keine abgerundeten Ecken und Schatteneffekte.
Sanket Berde
7
@ SanketBerde Genau. Denn genau das ist der "flache" Knopf.
Kiruwka
2
Die ursprüngliche Frage erwähnte nicht flach. Übrigens, wenn Sie in Ihrer Lösung ein <CardView> -Eltern anstelle von <FrameLayout> haben, wird die resultierende Schaltfläche angehoben und hat Schatten. Dies funktioniert sogar in Pre-Lollipop-Versionen.
Sanket Berde
1
@SanketBerde toll zu wissen, CardViewAnsatz, danke für das Teilen!
Kiruwka
88

Hier ist eine einfache und abwärtskompatible Methode, um erhöhten Tasten mit benutzerdefiniertem Hintergrund einen Welleneffekt zu verleihen.

Ihr Layout sollte so aussehen

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/my_custom_background"
    android:foreground="?android:attr/selectableItemBackground"/>
Bolein95
quelle
9
Dies ist der einfachste und unkomplizierteste Weg, dies zu erreichen. Gute Antwort.
Tyler Pfaff
1
API 21+ aber funktioniert nicht. Wird auf ein lineares Layout mit klickbar-wahr, Hintergrund - andere Farbe, Vordergrund angegeben.
Alex
3
Da Button eine Textansicht und kein FrameLayout ist, foregroundhat dies vor dem 23. google.com/…
androidguy
2
NETT! Ich wusste nicht einmal, dass "Vordergrund" eine Sache ist!
Eric Schlenz
2
Klappt wunderbar..!
Kannan
25

Ich bin heute auf dieses Problem gestoßen, als ich tatsächlich mit der v22-Bibliothek gespielt habe.

Angenommen, Sie verwenden Stile, können Sie die colorButtonNormalEigenschaft festlegen, und die Schaltflächen verwenden standardmäßig diese Farbe.

<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>

Abgesehen davon können Sie immer noch einen Stil für die Schaltfläche erstellen und diesen dann pro Schaltfläche verwenden, wenn Sie eine Auswahl an Farben benötigen (nicht getestet, nur spekuliert).

Denken Sie daran, android:vor den Elementnamen in Ihrem v21-Stil hinzuzufügen .

Robert Rose
quelle
Eine Auswahl farbiger Schaltflächen finden Sie in der Antwort anderer Roberts: stackoverflow.com/a/31825439/1617737
Ban-Geoengineering
Gibt es bei der jetzt festgelegten Hintergrundfarbe auch ein allgemeines Attribut, das ich im obigen Codeblock verwenden kann, um die Textfarbe der Schaltfläche anzugeben?
Ban-Geoengineering
24

Mit AppCompat (22.1.1+) können Sie einen Stil wie den folgenden hinzufügen:

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

Und verwenden Sie es, indem Sie einfach den Stil anwenden:

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

Beim programmgesteuerten Ändern der Farbe stellte ich fest, dass die einzige Möglichkeit zum Aktualisieren der Farbe (unter API 15 oder 16) darin bestand, stattdessen die 'Hintergrundtönungsliste' zu verwenden. Und die schöne radiale Animation auf API 21-Geräten wird nicht entfernt:

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

Weil button.setBackground(...)und button.getBackground().mutate().setColorFilter(...)ändern Sie die Schaltflächenfarbe in API 15 und 16 nicht wie in API 21.

Robert
quelle
1
Vielen Dank, es hat perfekt für mich funktioniert (auch wenn die Verwendung von Button in XML-Layouts als AppCompat Inflater es durch AppCompatButton ersetzt)
Louis CAD
1
Verwenden Sie ColorStateList.valueOf( ... )diese Option , um eine einfache ColorStateListFarbe mit nur einer Farbe zu erstellen.
Taig
colorAccent und rippleColor funktionieren nicht im Stil
Yar
Vielen Dank für diesen Beitrag. Was für mich funktioniert hat: ViewCompat.setBackgroundTintList(myButton, ColorStateList.valueOf(myColor); Javadoc für setSupportBackgroundTintListsagt, es sollte so heißen.
JerabekJakub
22

Die Antwort von @ ianhanniballake ist absolut korrekt und einfach. Aber ich habe ein paar Tage gebraucht, um zu verstehen. Für jemanden, der seine Antwort nicht versteht, ist hier eine detailliertere Implementierung

<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>

=== Oder ===

<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>
Frank Nguyen
quelle
5
Ihre Antwort war für mich das letzte Puzzleteil. Man kann auch colorButtonNormalin das Basisthema schreiben @style/AppTheme. Dies gibt AppCompat eine Standardfarbe, um die Schaltflächen entsprechend zu färben. Und dann können Sie Ihre Antwort verwenden, um eine Ansicht individuell zu gestalten.
Siddharth Pant
1
Ist es android:theme="Theme.MaterialButton"oderandroid:theme="@style/Theme.MaterialButton"
osrl
1
@osrl Es ist android:theme="@style/Theme.MaterialButton". Vielen Dank für Ihre Richtigkeit.
Frank Nguyen
12

Ich habe den backgroundTint und den Vordergrund verwendet:

<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"/>
SpyZip
quelle
afaik gibt es keine Notwendigkeit für das Vordergrundattribut, da backgroundTint die Standardwelligkeit nicht überschreibt
Julian Os
7

Ich bin zu diesem Beitrag gekommen, um nach einer Möglichkeit zu suchen, eine Hintergrundfarbe von mir zu haben ListView Artikel zu erhalten, aber die Welligkeit beizubehalten.

Ich habe einfach meine Farbe als Hintergrund und das selectableItemBackground als Vordergrund hinzugefügt:

<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>

und es funktioniert wie ein Zauber. Ich denke, die gleiche Technik könnte auch für Knöpfe verwendet werden. Viel Glück :)

Joakim
quelle
6

Wenn Sie an ImageButton interessiert sind, können Sie diese einfache Sache ausprobieren:

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

v22.1von ein appcompat-v7paar neue Möglichkeiten vorgestellt. Jetzt ist es möglich, ein bestimmtes Thema nur einer Ansicht zuzuweisen.

Veraltete Verwendung der App: Thema für die Gestaltung der Symbolleiste. Sie können jetzt android: theme für Symbolleisten auf allen Geräten der API-Stufe 7 und höher und android: theme für alle Widgets auf Geräten der API-Stufe 11 und höher verwenden.

Anstatt die gewünschte Farbe in einem globalen Thema festzulegen, erstellen wir eine neue und weisen sie nur dem zu Button

Beispiel:

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

Und verwenden Sie diesen Stil als Thema Ihrer Button

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

Wenn Sie mit der Verwendung einer Bibliothek eines Drittanbieters einverstanden sind , lesen Sie traex / RippleEffect . Mit nur wenigen Codezeilen können Sie JEDER Ansicht einen Ripple-Effekt hinzufügen . Sie müssen nur das Element, mit dem Sie einen Welleneffekt erzielen möchten, in Ihre XML-Layoutdatei einbindencom.andexert.library.RippleView Container .

Als zusätzlichen Bonus ist Min SDK 9 erforderlich, damit Sie über alle Betriebssystemversionen hinweg konsistent gestalten können.

Hier ist ein Beispiel aus dem GitHub-Repo der Bibliotheken:

<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>

Sie können die Welligkeitsfarbe ändern, indem Sie dieses Attribut dem RippleView-Element hinzufügen: app:rv_color="@color/my_fancy_ripple_color

guy.gc
quelle
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"/>

Verwenden

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

und die Farbe wird auf Pre-Lolipop acept

André Bäuml
quelle
2

In dem großartigen Tutorial von Alex Lockwood werden zwei Ansätze erläutert: http://www.androiddesignpatterns.com/2016/08/coloring-buttons-with-themeoverlays-background-tints.html :

Ansatz 1: Ändern der Hintergrundfarbe der Schaltfläche mit einem 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"/>

Ansatz 2: Festlegen des Hintergrundfarbtons des 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"/>
Makovkastar
quelle
2

Programmgesteuertes Anwenden der Farben:

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
Marlon
quelle
-1

Ich habe es versucht:

android:backgroundTint:"@color/mycolor"

anstatt die Hintergrundeigenschaft zu ändern. Dadurch wird der Materialeffekt nicht beseitigt.

Shiladitya
quelle
Dies funktioniert nicht für Geräte vor Lollipop (70% Marktanteil). Eigentlich wurde es zurückportiert, aber Android Studio zeigt ab sofort immer noch Fehler an, wenn es ohne das Android-Präfix verwendet wird.
Siddharth Pant