Odcień tła Lollipopa nie ma wpływu na przycisk

83

Mam przycisk w moim działaniu i chciałbym, aby miał kolor akcentu mojego motywu. Zamiast tworzyć własne elementy do rysowania, tak jak musieliśmy to zrobić przed Lollipopem, naturalnie chciałbym użyć nowego backgroundTintatrybutu.

<Button
    android:id="@+id/btnAddCode"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:backgroundTint="@color/accent"
    android:text="@string/addressInfo_edit_addCode" />

Niestety nie daje to efektu, przycisk pozostaje szary.

Próbowałem różnych wartości backgroundTintMode, które niczego nie zmieniały.

Próbowałem też zrobić to programowo w mojej Aktywności, co niczego nie zmieniło.

addCodeView.findViewById(R.id.btnAddCode).setBackgroundTintList(
     getResources().getColorStateList(R.color.accent));

Dlaczego mój odcień jest ignorowany?

EDYCJA: Żeby wyjaśnić, rzeczywiście testuję na urządzeniu Lollipop. Inne widżety (np. EditText) są poprawnie i automatycznie przyciemniane.

BoD
źródło
3
Jest to błąd, który został naprawiony w przyszłej wersji, ale zaakceptowane rozwiązanie będzie działać na API 21+.
alanv
sprawdź tę zaktualizowaną odpowiedź
Amit Vaghela

Odpowiedzi:

18

Testowane na API 19 do API 27

<?xml version="1.0" encoding="utf-8"?>
  <android.support.v7.widget.AppCompatButton 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    style="@style/Widget.AppCompat.Button.Colored"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/retry"
    android:textColor="@android:color/white"
    app:backgroundTint="@android:color/holo_red_dark" />

wytwarza wynik jako -

wprowadź opis obrazu tutaj

Sahitya Pasnoor
źródło
Oznaczając to jako zaakceptowaną odpowiedź, ponieważ po kilku latach uważam, że jest to obecnie oficjalny (i najlepszy) sposób na zrobienie tego. (Drobny szczegół: jestem prawie pewien, że w większości przypadków możesz po prostu użyć przycisku zamiast AppCompatButton i nadal będzie działać).
BoD
118

Złe wiadomości

Jak mówi BoD, zabarwienie tła przycisku w Lollipop 5.0 (poziom API 21) nie ma sensu.

Dobre wieści

Wydaje się, że Lollipop 5.1 (poziom API 22) naprawił ten problem, zmieniając btn_mtrl_default_shape.xml (między innymi): https://android.googlesource.com/platform/frameworks/base/+/6dfa60f33ca6018959ebff1efde82db7d2aed1e3%5E!/#F

Wspaniała wiadomość

Nowa biblioteka obsługi (wersja 22.1+) dodaje obsługę odcieni kompatybilną wstecz do wielu komponentów, w tym AppCompatButton !

Niestety android:backgroundTintwłaściwość nadal nie działa (może robię coś źle) - więc musisz ustawić ColorStateListkod używając setSupportBackgroundTintList(). Byłoby naprawdę miło widzieć android:backgroundTintwsparcie w przyszłości. Aktualizacja : Marcio Granzotto skomentował, że app:backgroundTintdziała na AppCompatButton! Zauważ, że tak app:nie jest android:, ponieważ znajduje się w aplikacji / bibliotece.

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <AppCompatButton
        android:id="@+id/mybutton"
        android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="Testing, testing"
        app:backgroundTint="#ff00ff"/>

</LinearLayout>

Twoja aktywność automatycznie zawyżnie wartość AppCompatButtonzamiast normalnej, Buttonjeśli pozwolisz jej dziedziczyć AppCompatActivity.

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        AppCompatButton v = (AppCompatButton) findViewById(R.id.mybutton);
        ColorStateList csl = new ColorStateList(new int[][]{new int[0]}, new int[]{0xffffcc00});
        v.setSupportBackgroundTintList(csl);
    }
}

Powinieneś oczywiście pobrać ColorStateListz zasobu koloru, ale byłem leniwy, więc ...

Aha, i nie zapomnij oprzeć motywu aplikacji na jednym z Theme.AppCompatmotywów, w przeciwnym razie widoki kompatybilności będą bardzo, bardzo smutne ...;)

To zadziałało zarówno na 2.3.7 (Gingerbread MR1), jak i 5.0 (Lollipop „Classic”).

Snild Dolkow
źródło
1
Właśnie dodałem więcej informacji - co najważniejsze, teraz można uzyskać przyciemnienie przycisków w nowej wersji (22.1) biblioteki wsparcia, która została wydana poprzedniego dnia!
Snild Dolkow
8
Możesz używać colorButtonNormalz AppCompat 22.1.1 (ustawienie motywu tylko dla przycisków), działa u mnie na 4.4.4 i 5.1.
hunyadym
2
Masz jakiś pomysł, jak ustawić to samo dla TextView?
programista Androida
8
Zamiast new ColorStateList(new int[][]{new int[0]}, new int[]{0xffffcc00});ty możesz pisać bardziej zwięźle ColorStateList.valueOf(0xffffcc00);.
Ashkan Sarlak
5
Możesz użyć android.support.v7.widget.AppCompatButton z app: backgroundTint na xml
Marcio Granzotto
30

Wydaje się, że zabarwienie rysowanego tętnienia jest bez znaczenia (a domyślnym tłem przycisku jest rysowanie tętnienia).

W rzeczywistości, po obejrzeniu domyślnego przycisku platformy do rysowania, znalazłem „prawidłowy” sposób, aby to zrobić: Musisz to zdefiniować w swoim motywie:

    <item name="android:colorButtonNormal">@color/accent</item>

(Oczywiście dotyczy to tylko poziomu 21+.)

Ostrzeżenie: ponieważ jest to zdefiniowane w motywie, spowoduje to użycie danego koloru dla wszystkich przycisków (przynajmniej wszystkich przycisków w działaniach wykorzystujących ten motyw).

Jako bonus możesz również zmienić kolor tętnienia, definiując to:

    <item name="android:colorControlHighlight">@color/accent_ripple</item>
BoD
źródło
colorControlHighlightzmieniłoby jednak wiele innych widżetów. Cieszę się, że to rozpracowałeś.
natario
5
Można to zastosować do pojedynczego widoku, definiując motyw nakładki (np. Brak motywu nadrzędnego i zdefiniowany tylko jeden atrybut) i używając atrybutu android: theme.
alanv
1
Więc jak to jest naprawione dla API 22 i nowszych? Również ten „błąd” występuje tylko w niektórych urządzeniach API 21 (w tym Nexus 5, galaxy s3)
data wysłania
22

Aby rozwiązać problemy związane z przyciemnianiem w systemie Android 5.0.x, używam czegoś takiego:

public static void setButtonTint(Button button, ColorStateList tint) {
    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP && button instanceof AppCompatButton) {
        ((AppCompatButton) button).setSupportBackgroundTintList(tint);
    } else {
        ViewCompat.setBackgroundTintList(button, tint);
    }
}

Używa metody wsparcia tylko dla API 21 i ViewCompat dla wszystkich innych przypadków.

GUG
źródło
@Marco Use:if (view instanceof TintableBackgroundView) { ((TintableBackgroundView) view).setSupportBackgroundTintList(tint); } else { ViewCompat.setBackgroundTintList(view, tint); }
chessdork
To nie działa z ImageButton na urządzeniach wcześniejszych niż Lollipop.
toobsco42
Otrzymuję ostrzeżenie o kłaczkach podczas korzystania z AppCompatButton.setSupportBackgroundTintList () AppCompatButton.setSupportBackgroundTintList można wywołać tylko z tej samej grupy bibliotek (groupId = com.android.support)
starkej2
U mnie zadziałało, ale musiałem odwrócić warunki.
Rodrigo Venancio
„można wywołać tylko z tej samej grupy bibliotek (groupId = com.android.support” dlaczego to ostrzeżenie?
Ferran Negre
22

Zwykle robię to dynamicznie za pomocą PorterDuff:

mbutton = (Button) findViewById(R.id.mybutton);
mbutton.getBackground().setColorFilter(anycolor, PorterDuff.Mode.MULTIPLY);

Możesz sprawdzić różne tryby mieszania tutaj i ładne przykłady tutaj .

Carlos Borau
źródło
1
Użyłem PorterDuff.Mode.SRC i działa idealnie
francisco_ssb
Działa świetnie. W moim przypadku chciałem użyć efektu barwienia na API 17, to mi pomogło.
ashishdhiman 2007,
2
To powinna być akceptowana odpowiedź. Potwierdź pracę nad API 20.
hardanger
19

Po prostu użyj app:backgroundTintzamiast android:backgroundTint, odcień zacznie obowiązywać poniżej Lollipopa. Powodem jest AppCompatActivityużycie AppCompatViewInflaterautomatycznej zmiany Button lub TextView na AppCompatButton lub AppCompatTextView, a następnie app:backgroundTintzastosowanie.

wprowadź opis obrazu tutaj

W moim projekcie wykorzystałem to, zadziałało.

kaczor
źródło
9

Myślę, że musisz android:backgroundsię przygotowaćandroid:backgroundTint pracy.

Aby być dokładniejszym, przypuszczam, że nie można ustawić backgroundTintdomyślnego tła przycisku z motywów Material, które jest zdefiniowane jako plik RippleDrawable.

natario
źródło
1
Myślę że masz rację. W rzeczywistości znalazłem „właściwy” sposób robienia tego, co chcę (zobacz moją odpowiedź).
BoD
3

Podobny problem został zgłoszony w Google https://code.google.com/p/android/issues/detail?id=201873

Ale po wydaniu biblioteki obsługi Androida, wersja 23.2.1 (marzec 2016) Ten błąd został rozwiązany.

Problem: FloatingActionButton.setBackgroundTintList (tinta @Nullable ColorStateList) nie zmienia już koloru tła

zaktualizuj bibliotekę pomocy do Android Support Library to 23.2.1

Użyj biblioteki wsparcia projektowania (23.2.1) i appcompatwidgets, jak poniżej

Material Design dla urządzeń Pre-Lollipop :

AppCompat (aka ActionBarCompat) zaczynał jako backport API Android 4.0 ActionBar dla urządzeń działających na Gingerbread, zapewniając wspólną warstwę API na szczycie implementacji backportowanej i implementacji frameworka. AppCompat v21 zapewnia interfejs API i zestaw funkcji, które są aktualne w systemie Android 5.0


Biblioteka obsługi Androida 22.1 :

Możliwość automatycznego przyciemniania widżetów podczas korzystania z AppCompat jest niezwykle pomocna w utrzymaniu silnej marki i spójności w całej aplikacji. Odbywa się to automatycznie podczas zawyżania układów - zastępując Button z AppCompatButton, TextView z AppCompatTextView itp., Aby upewnić się, że każdy może obsługiwać tinting. W tej wersji te widżety obsługujące tintę są teraz publicznie dostępne, co pozwala na utrzymanie ich obsługi nawet w przypadku konieczności podklasy jednego z obsługiwanych widgetów.

Amit Vaghela
źródło
3

Po prostu użyj app: backgroundTint zamiast android: backgroundTint

Smirnov Sergey
źródło
2

Jeśli spojrzymy na kod źródłowy Support Library, zobaczymy, że normalnie zabarwia to znane przyciski, ale jeśli zmienimy kształt naszego przycisku (mam okrągły przycisk), odcień nie działa poprawnie w api <= 21. Widzimy również, że TintManager stał się klasą publiczną (appcompat-v7: 23.1.1), więc możemy pobrać ColorStateList z domyślnego kształtu przycisku (który jest przyciemniony w wersji 5.0) dla bieżącego motywu (więc nie musimy tworzyć tablicy kolorów):

    Context c = ...; // activity
    AppCompatButton ab = ...; // your button
    // works ok in 22+:
    if (Build.VERSION.SDK_INT <= 21) {
        // default appcompat button, that is tinted ok with current theme colors "abc_btn_default_mtrl_shape":
        // ColorStateList tint = TintManager.get(c).getTintList(R.drawable.abc_btn_default_mtrl_shape);
        // Appcompat 23.2 change:
        ColorStateList tint = AppCompatDrawableManager.get().getTintList(c, R.drawable.abc_btn_default_mtrl_shape);
        ab.setSupportBackgroundTintList(tint);
        }
Pavel Biryukov
źródło
od AppCompat 23,2 zmienili klasę (chociaż jej publicznie!) TintManager -> AppCompatDrawableManager kod pozostanie prawie taka sama
Pavel Biryukov
WTF ... zmieniono getTintList z publicznego na chroniony teraz; (trzeba użyć odbicia :)
Pavel Biryukov
0

Ponieważ atrybut backgroundTintjest używany tylko na poziomie interfejsu API 21 i wyższych

fedache
źródło
Zdaję sobie z tego sprawę i rzeczywiście testuję na urządzeniu Lollipop. Zaktualizuję pytanie, aby było jasne.
BoD
0

Należy pamiętać, że najbardziej zaktualizowana biblioteka z recyklingiem może spowodować ten błąd.

To polecenie

  sendBtnView.setBackgroundTintList(colorState)

działał doskonale w przeszłości, ale przestań dla mnie działać. po badaniach okazuje się, że przyczyną jest biblioteka dodana do zależności gradle:

  compile 'com.android.support:recyclerview-v7:+'

Próbowałem więc zmienić to na 23.02.1, tak jak było to zalecane tutaj w poście Amit Vaghela. Zmieniłem się

  compile  'com.android.support:recyclerview-v7:23.02.1'

Ale błąd gradle powiedział, że recyclinglerview lib nie ma tej wersji (23.02.1) (gradle nie mógł jej znaleźć w Jcenter raw.github lub repo).

Następnie, ponieważ wiedziałem, że komenda setBackgroundTintList działała dobrze w przeszłości z wersją 22.02.0 'we wszystkich innych bibliotekach, które mam w zależnościach gradle. więc zmieniam to na:

compile   'com.android.support:recyclerview-v7:22.02.0'

A teraz znowu działa.

Udi Reshef
źródło
0

Nie jestem pewien, czy jest to zalecane, ale możesz spróbować tego:

Drawable newDrawable = mBtnAction.getBackground();  // obtain Bg drawable from the button as a new drawable
DrawableCompat.setTint(newDrawable, mActivity.getHomeTobBarBGColor());  //set it's tint
mBtnAction.setBackground(newDrawable);  //apply back to button

W ogólnym sensie to działa. Próbowałem, ViewCompatale nie wydaje się działać poprawnie.

sud007
źródło
0

możesz używać backgroundTint <android.support.design.button.MaterialButtonz "com.android.support:design:28.0.0-rc01"wersją

Zafer Celaloglu
źródło
0

Jeśli używasz Androidax, dodanie wersji z prefiksem i bez prefiksu rozwiązało problem w systemie Android 5.1:

<style name="Button_Primary">
    <item name="android:layout_height">wrap_content</item>
    <item name="android:layout_width">wrap_content</item>
    <item name="android:backgroundTint">@color/button_primary_selector</item>
    <item name="backgroundTint">@color/button_primary_selector</item><!--needed for android 5-->
</style>

Selektor button_primary znajduje się w colorfolderze z następującą zawartością:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:local="http://schemas.android.com/apk/res-auto">
    <item android:state_enabled="true" android:color="@android:color/holo_blue_dark" />
    <item android:state_enabled="false" android:color="@android:color/darker_gray" />
</selector>

i zastosuj go na zwykłym przycisku AppCompatActivity

<Button style="@style/Button_Primary"/>
Chytry
źródło