Jak programowo dodać odcień przycisków

120

W nowej bibliotece AppCompat możemy zabarwić przycisk w ten sposób:

<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/follow"
    android:id="@+id/button_follow"
    android:backgroundTint="@color/blue_100"
    />

Jak mogę programowo ustawić odcień przycisku w moim kodzie? Zasadniczo próbuję zaimplementować warunkowe kolorowanie przycisku na podstawie danych wejściowych użytkownika.

Stephane
źródło
Czy na pewno Android: backgroundTint działa na Pre-Lollipop? Testuję zarówno z Button, jak i ApCompatButton, ale backgroundTint wydaje się działać tylko na Lollipop.
Sharj
1
Proszę sprawdzić tę odpowiedź .
Amit Vaghela

Odpowiedzi:

162

Zgodnie z dokumentacją powiązaną metodą android:backgroundTintjest setBackgroundTintList (lista ColorStateList)

Aktualizacja

Skorzystaj z tego łącza, aby dowiedzieć się, jak utworzyć zasób listy stanów kolorów.

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:color="#your_color_here" />
</selector>

następnie załaduj go za pomocą

setBackgroundTintList(contextInstance.getResources().getColorStateList(R.color.your_xml_name));

gdzie contextInstancejest wystąpieniemContext


przy użyciu AppCompart

btnTag.setSupportButtonTintList(ContextCompat.getColorStateList(Activity.this, R.color.colorPrimary));
Zimny ​​ogień
źródło
który nie jest kolorem, ale ColorStateList. Jak to wykorzystać?
Stephane
4
Teraz rozumiem, jak to zrobić, ale dlaczego Android miałby nie pozwolić na ręczne użycie koloru? Dla każdego koloru każdego przycisku, który mam, będę musiał utworzyć xml dla ColorStateList? Wydaje mi się, że to strata
Stephane
2
setBackgroundTintList wymaga interfejsu API 21, nawet jeśli wywołasz go w AppCompatButton.
Sharj
29
Biblioteka wsparcia AppCompat oferuje statyczny pomocnik: ViewCompat.setBackgroundTintList(View, ColorStateList)może być używany aż do API 4. Ale działa tylko dla widoków, które implementują TintableBackgroundViewna przykład AppCompatButton(zamiast zwykłych Button).
Jon Adams,
1
Teraz używanie ViewCompat.setBackgroundTintList(View, ColorStateList), jak zasugerował @Jon Adams, ma jeszcze większy sens, ponieważ View.setSupportButtonTintList jest ograniczone do RestrictToadnotacji. Szczegóły tutaj: developer.android.com/reference/android/support/annotation/…
AlexKost
75

Możesz użyć

button.setBackgroundTintList(ColorStateList.valueOf(resources.getColor(R.id.blue_100)));

Ale poleciłbym ci skorzystanie z biblioteki obsługi barwienia do rysowania, która właśnie została wydana wczoraj:

Drawable drawable = ...;

// Wrap the drawable so that future tinting calls work
// on pre-v21 devices. Always use the returned drawable.
drawable = DrawableCompat.wrap(drawable);

// We can now set a tint
DrawableCompat.setTint(drawable, Color.RED);
// ...or a tint list
DrawableCompat.setTintList(drawable, myColorStateList);
// ...and a different tint mode
DrawableCompat.setTintMode(drawable, PorterDuff.Mode.SRC_OVER);

Więcej informacji można znaleźć w tym poście na blogu (patrz sekcja „Barwienie do rysowania”)

dimsuz
źródło
2
może u podać pełny kod, aby ustawić odcień przy użyciu metody ur?
M. Usman Khan
Najlepsza odpowiedź...!
Gokul Nath KP
60

Wygląda na to, że widoki mają własną mechanikę zarządzania odcieniami, więc lepiej będzie umieścić listę odcieni:

ViewCompat.setBackgroundTintList(
    editText, 
    ColorStateList.valueOf(errorColor));
tse
źródło
Znacznie lepiej, używając tego w ten sposób, dzięki czemu uzyskasz kompatybilność wsteczną z API 4!
xarlymg89
jedno z najlepszych rozwiązań.
Atif AbbAsi
21

W poprawnym rozszerzeniu odpowiedzi dimsuza przez podanie rzeczywistej sytuacji w kodzie, zobacz następujący fragment kodu:

    Drawable buttonDrawable = button.getBackground();
    buttonDrawable = DrawableCompat.wrap(buttonDrawable);
    //the color is a direct color int and not a color resource
    DrawableCompat.setTint(buttonDrawable, Color.RED);
    button.setBackground(buttonDrawable);

To rozwiązanie jest dla scenariusza, w którym element rysunkowy jest używany jako tło przycisku. Działa również na urządzeniach sprzed wersji Lollipop.

Shayne3000
źródło
@TruptiNasit Miło to słyszeć.
Shayne3000
Pracował dla mnie. Dziękuję Ci.
wesley franks
1
@wesleyfranks Nie ma za co. Miło słyszeć, że zadziałało.
Shayne3000,
7

Czy próbowałeś czegoś takiego?

button.setBackgroundTintList(getResources().getColorStateList(R.id.blue_100));

pamiętaj, że getResources () będzie działać tylko w działaniu. Ale można go również wywołać w każdym kontekście.

Chris K.
źródło
Możesz utworzyć plik XML zgodnie z opisem tutaj: developer.android.com/reference/android/content/res/…
Chris K.
getColorStateList wydaje się być przestarzałe.
cloudsurfin
1
setBackgroundTintList wydaje się wymagać poziomu API 21
Nashe
1
przycisk. setBackgroundTintList (ContextCompat.getColorStateList (kontekst, R.color.blue)); pracował dla mnie
jesto paul
7

oto jak to zrobić w kotlinie:

view.background.setTint(ContextCompat.getColor(context, textColor))
Amin Keshavarzian
źródło
1
dzięki, działało dobrze!
Stoica Mircea
To powinna być odpowiedź. Dzięki!
Andrei Vinogradov
5

Możesz użyć DrawableCompat np

public static Drawable setTint(Drawable drawable, int color) {
    final Drawable newDrawable = DrawableCompat.wrap(drawable);
    DrawableCompat.setTint(newDrawable, color);
    return newDrawable;
}
mac229
źródło
5

można to łatwo obsłużyć w nowym przycisku Material z biblioteki Material Design, najpierw dodaj zależność:

implementation 'com.google.android.material:material:1.1.0-alpha07'

następnie w swoim kodzie XML użyj tego jako przycisku:

<com.google.android.material.button.MaterialButton
    android:id="@+id/accept"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/i_accept"
    android:textSize="18sp"
    app:backgroundTint="@color/grayBackground_500" />

a jeśli chcesz zmienić kolor, oto kod w Kotlinie, nie jest przestarzały i można go używać przed Androidem 21:

accept.backgroundTintList = ColorStateList.valueOf(ResourcesCompat.getColor(resources, 
R.color.colorPrimary, theme))
Amin Keshavarzian
źródło
Czy istnieje podobny odcień samego tekstu?
programista Androida
masz na myśli tekst jako przycisk i chcesz zmienić kolor tła?
Amin Keshavarzian,
4

Mój sposób, w jaki udało mi się zmusić do pracy, polegał na użyciu CompoundButtonCompat.setButtonTintList(button, colour).

W moim rozumieniu działa to niezależnie od wersji Androida.

Matt Jenje
źródło
3

Miałem podobny problem. Chciałem pokolorować złożone, możliwe do rysowania tło dla widoku na podstawie wartości koloru (int). Udało mi się, używając kodu:

ColorStateList csl = new ColorStateList(new int[][]{{}}, new int[]{color});
textView.setBackgroundTintList(csl);

Gdzie kolor jest wartością int reprezentującą wymagany kolor. To reprezentuje prostą xml ColorStateList:

<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:color="color here"/>
</selector>

Mam nadzieję że to pomoże.

Pokaż swoją pracę
źródło
2
Minimalny wymagany poziom API 21
forsberg
cóż, możesz po prostu użyćColorStateList.valueOf(ColorInt)
user924,
2

W przypadku ImageButton możesz użyć:

favoriteImageButton.setColorFilter(Color.argb(255, 255, 255, 255)); // White Tint
Saurabh Singh
źródło
setColorFilter nie jest zdefiniowany dla Buttons
Jérémy
To jest dla ImageButton.
Saurabh Singh
O ok, nie wiedziałem o tym. Ale OP prosi o Button. Czy możesz edytować swoją odpowiedź, podając te szczegóły, abym mógł usunąć mój głos przeciw?
Jérémy
2

Jeśli używasz Kotlini Material Design, możesz zmienić kolor swojego w MaterialButtonten sposób:

myButton.background.setTintList(ContextCompat.getColorStateList(context, R.color.myColor))

Możesz to ulepszyć jeszcze lepiej, tworząc funkcję rozszerzenia dla swojego MaterialButtonkodu, aby kod był bardziej czytelny, a kodowanie trochę wygodniejsze:

fun MaterialButton.changeColor(color: Int) {
    this.background.setTintList(ContextCompat.getColorStateList(context, color))
}

Następnie możesz używać swojej funkcji wszędzie w ten sposób:

myButton.changeColor(R.color.myColor)
Azizjon Kholmatov
źródło
1

Oprócz odpowiedzi Shayne3000 możesz również użyć zasobu koloru (nie tylko int color). Wersja Kotlin :

var indicatorViewDrawable = itemHolder.indicatorView.background
indicatorViewDrawable = DrawableCompat.wrap(indicatorViewDrawable)
val color = ResourcesCompat.getColor(context.resources, R.color.AppGreenColor, null) // get your color from resources
DrawableCompat.setTint(indicatorViewDrawable, color)
itemHolder.indicatorView.background = indicatorViewDrawable
coldembrace
źródło
0

Sugerowana odpowiedź tutaj nie działa poprawnie w systemie Android 5.0, jeśli lista stanów kolorów oparta na XML odwołuje się do atrybutów tematycznych. Na przykład mam listę stanów kolorów XML, taką jak ta:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="?colorPrimary" android:state_enabled="true"/>
    <item android:alpha="0.12" android:color="?attr/colorOnSurface"/>
</selector>

Używanie tego jako mojego backgroundTint z xml działa dobrze na Androidzie 5.0 i wszystkim innym. Jeśli jednak spróbuję ustawić to w kodzie w ten sposób:

(Nie rób tego)

myButton.setSupportButtonTintList(ContextCompat.getColorStateList(myButton.getContext(), R.color.btn_tint_primary));

Właściwie nie ma znaczenia, czy przekażę Activity lub kontekst przycisku do metody ContextCompat.getColorStateList (), ani nie poda mi właściwej listy stanów kolorów w odniesieniu do motywu, w którym znajduje się przycisk. Dzieje się tak, ponieważ używanie atrybutów motywu na listach stanu kolorów nie było obsługiwane przed api 23, a ContextCompat nie robi nic specjalnego, aby je rozwiązać. Zamiast tego należy użyć AppCompatResources.getColorStateList (), która wykonuje własne analizowanie zasobów / rozpoznawanie atrybutów motywu na urządzeniach <API 23.

Zamiast tego musisz użyć tego:

myButton.setSupportBackgroundTintList(AppCompatResources.getColorStateList(myButton.getContext(), R.color.btn_tint_primary));

TLDR: użyj AppCompatResources, a nie -ContextCompat-, jeśli potrzebujesz rozwiązanych zasobów tematycznych we wszystkich wersjach interfejsu API Androida.

Więcej informacji na ten temat znajdziesz w tym artykule .

Matt Wolfe
źródło