Standardowy przycisk Androida w innym kolorze

735

Chciałbym nieznacznie zmienić kolor standardowego przycisku Androida, aby lepiej pasował do marki klienta.

Najlepszym sposobem, jaki do tej pory znalazłem, jest zmiana Buttonszuflady na szufladę w res/drawable/red_button.xml:

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

Ale zrobienie tego wymaga stworzenia trzech różnych drawables dla każdego przycisku, który chcę dostosować (jeden dla przycisku w spoczynku, jeden po skupieniu i jeden po naciśnięciu). To wydaje się bardziej skomplikowane i pozbawione SUSZENIA niż potrzebuję.

Wszystko, co naprawdę chcę zrobić, to zastosować jakąś transformację kolorów do przycisku. Czy jest łatwiejszy sposób na zmianę koloru przycisku niż ja?

emmby
źródło
I tutaj także android.onyou.ch/2011/01/25/…
Pankaj Kumar

Odpowiedzi:

723

Odkryłem, że można to dość łatwo zrobić w jednym pliku. Umieść coś takiego jak poniższy kod w pliku o nazwie, custom_button.xmla następnie ustaw background="@drawable/custom_button"w widoku przycisków:

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

    <item android:state_pressed="true" >
        <shape>
            <gradient
                android:startColor="@color/yellow1"
                android:endColor="@color/yellow2"
                android:angle="270" />
            <stroke
                android:width="3dp"
                android:color="@color/grey05" />
            <corners
                android:radius="3dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>
    </item>

    <item android:state_focused="true" >
        <shape>
            <gradient
                android:endColor="@color/orange4"
                android:startColor="@color/orange5"
                android:angle="270" />
            <stroke
                android:width="3dp"
                android:color="@color/grey05" />
            <corners
                android:radius="3dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>
    </item>

    <item>        
        <shape>
            <gradient
                android:endColor="@color/blue2"
                android:startColor="@color/blue25"
                android:angle="270" />
            <stroke
                android:width="3dp"
                android:color="@color/grey05" />
            <corners
                android:radius="3dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>
    </item>
</selector>
emmby
źródło
42
Działa to dobrze w przypadku koloru tła - czy możesz ustawić kolor tekstu w ten sam sposób?
Rachel
8
To daje mi "Error: No resource found that matches the given name (at 'color' with value '@color/yellow1')" Czy są to odniesienia do wbudowanych kolorów? wydaje się, że potrzebuję res / wartości / color.xml, aby to zadziałało
Harry Wood
8
@HarryWood musisz zdefiniować te kolory w swoim res / values ​​/ colors.xml. Alternatywnie, zamień je na „# ff0000”, „# 00ff00”, do celów testowych @ cfarm54 Plik ten należy umieścić w folderze res / drawable / custom_button.xml @emmby Dziękujemy za fragment kodu!
espinchi
17
Świetny wskaźnik, dzięki! Pamiętaj też, że dla innych osób próbujących tego, kolejność elementów w selektorze jest znacząca. Jeśli najpierw umieścisz <item> bez filtrów stanu w pliku, zastąpi on resztę.
mikerowehl
9
aby to zadziałało, umieść custom_button.xml w folderze res / „drawable” - i utwórz plik res / wartości / colors.xml z następującą zawartością: stackoverflow.com/questions/3738886/… - zmień nazwy kolorów w dowolnym pliku aby działało
sami
308

Zgodnie z odpowiedzią Tomasza możesz również programowo ustawić odcień całego przycisku za pomocą trybu zwielokrotnienia PorterDuff. Spowoduje to zmianę koloru przycisku, a nie tylko odcień.

Jeśli zaczniesz od standardowego szarego zacienionego przycisku:

button.getBackground().setColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY);

da ci czerwony cieniowany przycisk,

button.getBackground().setColorFilter(0xFF00FF00, PorterDuff.Mode.MULTIPLY);

da ci zielony przycisk zacieniowany itp., gdzie pierwszą wartością jest kolor w formacie szesnastkowym.

Działa poprzez pomnożenie bieżącej wartości koloru przycisku przez wartość koloru. Jestem pewien, że dzięki tym trybom możesz zrobić znacznie więcej.

kierunek sprzężony
źródło
2
Wow, właśnie tego wypróbowałem i jest to całkowicie fantastyczne. Dziękuję Ci! Czy zdarza ci się wiedzieć, czy istnieje sposób, aby to jakoś osiągnąć za pomocą XML?
emmby,
4
Chłopaki, sprawdźcie w HTC Desire! Mają różne standardowe przyciski. Moje przyciski używające tego kodu wyglądają tam niepoprawnie GDY ustawiają określoną szerokość_ładu, np. „40dp”. Z „wrap_content” jest w porządku.
OneWorld,
5
Potwierdzono, że to rozwiązanie nie działa bardzo dobrze w interfejsie HTC Sense
emmby
19
Zaćmienie nie pokazuje tego jako możliwej poprawki:import android.graphics.PorterDuff;
Someone Somewhere
2
Czy ktoś miał jakieś problemy z tym, że nie działa w ICS? Wydaje się, że nie działa dla mnie na emulatorze ani telefonie.
Stev_k
149

Mike, możesz być zainteresowany kolorowymi filtrami.

Przykład:

button.getBackground().setColorFilter(new LightingColorFilter(0xFFFFFFFF, 0xFFAA0000));

spróbuj tego, aby osiągnąć pożądany kolor.

Tomasz
źródło
Spróbuj przekazać null w metodzie setColorFilter. Nie próbowałem tego, ale powinno działać.
Tomasz
6
@Pacerier to unset: button.getBackground (). ClearColorFilter ();
Stan Kurdziel
3
Polecam wybranie koloru za pomocą klasy Color: developer.android.com/reference/android/graphics/Color.html
Mugen
Idealny do ciemnych motywów! Zakładam, że druga górna odpowiedź (setColorFilter (0xFFFF0000, PorterDuff.Mode.MULTIPLY)) działa lepiej w przypadku jasnych motywów.
java.is.for.desktop
85

To jest moje rozwiązanie, które doskonale działa począwszy od API 15 . To rozwiązanie zachowuje wszystkie domyślne efekty kliknięcia przycisku, takie jak materiał RippleEffect. Nie testowałem tego na niższych interfejsach API, ale powinno działać.

Wszystko, co musisz zrobić, to:

1) Utwórz styl, który zmienia się tylko colorAccent:

<style name="Facebook.Button" parent="ThemeOverlay.AppCompat">
    <item name="colorAccent">@color/com_facebook_blue</item>
</style>

Zalecam użycie ThemeOverlay.AppCompatlub głównego AppThemejako rodzica, aby zachować resztę swoich stylów.

2) Dodaj te dwa wiersze do buttonwidżetu:

style="@style/Widget.AppCompat.Button.Colored"
android:theme="@style/Facebook.Button"

Czasami Twój nowy colorAccentnie jest wyświetlany w wersji zapoznawczej Android Studio, ale po uruchomieniu aplikacji na telefonie kolor zostanie zmieniony.


Przykładowy widget przycisku

<Button
    android:id="@+id/sign_in_with_facebook"
    style="@style/Widget.AppCompat.Button.Colored"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:text="@string/sign_in_facebook"
    android:textColor="@android:color/white"
    android:theme="@style/Facebook.Button" />

Przykładowy przycisk z niestandardowym kolorem

RediOne1
źródło
1
Co robi ta linia? "style =" @ style / Widget.AppCompat.Button.Colored ""
Charles Li
2
Pomogło mi to zrozumieć różnicę między stylem a motywem. Dziękuję Ci.
rpattabi
2
Zaakceptowana odpowiedź jest poprawna, ale za stara. Ta jest prosta i najbardziej aktualna odpowiedź.
正宗 白 布鞋
Problem z tą odpowiedzią polega na tym, że ustawienie colorAccentwpływa nie tylko na tło przycisku.
Blcknx
@Blcknx Co na przykład?
RediOne1
61

Teraz można również użyć AppCompat NRPV7 za AppCompatButton z backgroundTintatrybutu:

<android.support.v7.widget.AppCompatButton
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:backgroundTint="#ffaa00"/>
Nilhcem
źródło
4
Nie działało dla mnie przy użyciu przestrzeni nazw „android:”. Ale zadziałało, gdy zamiast tego użyłem przestrzeni nazw „app:”.
David Velasquez,
@DavidVelasquez To działało również dla mnie na Androidzie Lollipop, podczas gdy Android: przestrzeń nazw nic nie zmieniła. Dzięki za pomoc!
Avinash Prabhakar
To jest najprostsze rozwiązanie i powinno być przyjętą odpowiedzią. Korzystanie z Androida: backgroundTint działa dla mnie.
Ramashish Baranwal
1
Musi być app:backgroundTintzamiast android:backgroundTintpodczas korzystania z AppCompat.
Hafez Divandari
23

Podoba mi się propozycja filtra kolorów w poprzednich odpowiedziach z @conjugatedirection i @Tomasz; Odkryłem jednak, że podany do tej pory kod nie był tak łatwy do zastosowania, jak się spodziewałem.

Po pierwsze, nie wspomniano, gdzie zastosować i wyczyścić filtr kolorów. Możliwe, że są inne dobre miejsca do zrobienia tego, ale przyszło mi do głowy OnTouchListener .

Z mojej lektury pierwotnego pytania idealnym rozwiązaniem byłoby takie, które nie wymaga żadnych zdjęć. Akceptowana odpowiedź przy użyciu custom_button.xml z @emmby jest prawdopodobnie lepszym rozwiązaniem niż filtry kolorów, jeśli taki jest twój cel. W moim przypadku zaczynam od obrazu png od projektanta interfejsu użytkownika, jak ma wyglądać przycisk. Jeśli ustawię tło przycisku dla tego obrazu, domyślna informacja o podświetleniu zostanie całkowicie utracona. Ten kod zastępuje to zachowanie programowym efektem zaciemnienia.

button.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 0x6D6D6D sets how much to darken - tweak as desired
                setColorFilter(v, 0x6D6D6D);
                break;
            // remove the filter when moving off the button
            // the same way a selector implementation would 
            case MotionEvent.ACTION_MOVE:
                Rect r = new Rect();
                v.getLocalVisibleRect(r);
                if (!r.contains((int) event.getX(), (int) event.getY())) {
                    setColorFilter(v, null);
                }
                break;
            case MotionEvent.ACTION_OUTSIDE:
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                setColorFilter(v, null);
                break;
        }
        return false;
    }

    private void setColorFilter(View v, Integer filter) {
        if (filter == null) v.getBackground().clearColorFilter();
        else {
            // To lighten instead of darken, try this:
            // LightingColorFilter lighten = new LightingColorFilter(0xFFFFFF, filter);
            LightingColorFilter darken = new LightingColorFilter(filter, 0x000000);
            v.getBackground().setColorFilter(darken);
        }
        // required on Android 2.3.7 for filter change to take effect (but not on 4.0.4)
        v.getBackground().invalidateSelf();
    }
});

Wyodrębniłem to jako osobną klasę do zastosowania na wielu przyciskach - pokazaną jako anonimowa klasa wewnętrzna, aby pojąć ten pomysł.

Stan Kurdziel
źródło
To było świetne rozwiązanie! Przeważnie sam wpływ, jak dostać się na iOS, która domyślnie jest to, co projektanci jak :-)
Christer Nordvik
próbowałem tego z 2 przyciskami na tym samym ekranie z tym samym tłem, a efekt dotyczy zarówno przycisku onTouch
Goofy
16

Jeśli tworzysz kolorowe przyciski za pomocą XML, możesz sprawić, że kod będzie trochę czystszy, określając stan skupienia i naciśnięcia w osobnym pliku i wykorzystując je ponownie. Mój zielony przycisk wygląda następująco:

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

    <item android:state_focused="true" android:drawable="@drawable/button_focused"/>
    <item android:state_pressed="true" android:drawable="@drawable/button_pressed"/>

    <item>
        <shape>
            <gradient android:startColor="#ff00ff00" android:endColor="#bb00ff00" android:angle="270" />
            <stroke android:width="1dp" android:color="#bb00ff00" />
            <corners android:radius="3dp" />
            <padding android:left="10dp" android:top="10dp" android:right="10dp" android:bottom="10dp" />
        </shape>
    </item>

</selector>
krwawy
źródło
1
miły. jak sprawić, by stan skupienia i naciśnięcia odwoływał się do standardowych definicji Androida dla przycisków?
larham1
Jestem pewien, że nie, ponieważ standardowe przyciski Androida są zaimplementowane jako mapy bitowe z 9 łatkami.
hemem
12

Najkrótsze rozwiązanie, które działa z dowolną wersją Androida:

<Button
     app:backgroundTint="@color/my_color"

Uwagi / wymagania :

  • Użyj app:nazw i nieandroid: nazw!
  • Wersja aplikacji> 24.2.0

    zależności {kompiluj 'com.android.support:appcompat-v7:25.3.1'}

Objaśnienie : wprowadź opis zdjęcia tutaj

użytkownik1185087
źródło
1
Co ciekawe, dla mnie app:backgroundTint="@color/my_color"nie działało. android:backgroundTint="@color/my_color"działało idealnie.
Igor,
To jest dla mnie najkrótsze i najczystsze rozwiązanie i to wszystko.
Marty
11

Korzystam z tego podejścia

style.xml

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:colorPrimaryDark">#413152</item>
    <item name="android:colorPrimary">#534364</item>
    <item name="android:colorAccent">#534364</item>
    <item name="android:buttonStyle">@style/MyButtonStyle</item>
</style>

<style name="MyButtonStyle" parent="Widget.AppCompat.Button.Colored">
    <item name="android:colorButtonNormal">#534364</item>
    <item name="android:textColor">#ffffff</item>
</style>

Jak widać z góry, używam niestandardowego stylu dla mojego przycisku. Kolor przycisku odpowiada kolorowi akcentu. Uważam to za znacznie lepsze podejście niż ustawienie, android:backgroundponieważ nie stracę efektu tętnienia, który zapewnia Google.

Kelok Chan
źródło
8

Jest teraz o wiele łatwiejszy sposób: android-holo-colors.com

Umożliwi to łatwą zmianę kolorów wszystkich holo drawables (guziki, pokrętła, ...). Wybierz kolor, a następnie pobierz plik zip zawierający pliki rysunkowe dla wszystkich rozdzielczości.

Dalmas
źródło
8

Użyj go w ten sposób:

buttonOBJ.getBackground().setColorFilter(Color.parseColor("#YOUR_HEX_COLOR_CODE"), PorterDuff.Mode.MULTIPLY);
IntelliJ Amiya
źródło
4

W <Button>użyciu android:background="#33b5e5". albo lepiejandroid:background="@color/navig_button"

lalitm
źródło
3

DroidUX biblioteka składnik ma ColorButtonwidget, którego kolor może być łatwo zmieniony, zarówno poprzez definicji XML i programowo w czasie wykonywania, więc można nawet pozwolić użytkownikowi ustaw przycisk Color / motywu jeśli aplikacja na to pozwala.

Ricky Lee
źródło
3

Możesz także użyć tego narzędzia online, aby dostosować przycisk http://angrytools.com/android/button/ i użyć android:background="@drawable/custom_btn"do zdefiniowania przycisku dostosowanego w układzie.

JRE.exe
źródło
2

Możesz ustawić motyw swojego przycisku do tego

<style name="AppTheme.ButtonBlue" parent="Widget.AppCompat.Button.Colored">
 <item name="colorButtonNormal">@color/HEXColor</item>
 <item name="android:textColor">@color/HEXColor</item>
</style>
Manoj Bhadane
źródło
1

Prostym sposobem jest po prostu zdefiniowanie niestandardowej klasy Button, która akceptuje wszystkie pożądane właściwości, takie jak promień, gradient, tłoczony kolor, normalny kolor itp., A następnie po prostu używa tego w układach XML zamiast konfigurować tło za pomocą XML. Próbka jest tutaj

Jest to niezwykle przydatne, jeśli masz wiele przycisków o takich samych właściwościach, jak promień, wybrany kolor itp. Możesz dostosować odziedziczony przycisk do obsługi tych dodatkowych właściwości.

Wynik (nie użyto selektora tła).

Normalny przycisk

Normalny obraz

Wciśnięty przycisk

wprowadź opis zdjęcia tutaj

redDragonzz
źródło
0

Sposób, w jaki robię przycisk w innym stylu, który działa całkiem dobrze, to podklasowanie obiektu Button i zastosowanie filtra kolorów. To również obsługuje stany włączone i wyłączone, stosując alfa do przycisku.

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.LightingColorFilter;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.Button;

public class DimmableButton extends Button {

    public DimmableButton(Context context) {
        super(context);
    }

    public DimmableButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

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

    @SuppressWarnings("deprecation")
    @Override
    public void setBackgroundDrawable(Drawable d) {
        // Replace the original background drawable (e.g. image) with a LayerDrawable that
        // contains the original drawable.
        DimmableButtonBackgroundDrawable layer = new DimmableButtonBackgroundDrawable(d);
        super.setBackgroundDrawable(layer);
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public void setBackground(Drawable d) {
        // Replace the original background drawable (e.g. image) with a LayerDrawable that
        // contains the original drawable.
        DimmableButtonBackgroundDrawable layer = new DimmableButtonBackgroundDrawable(d);
        super.setBackground(layer);
    }

    /**
     * The stateful LayerDrawable used by this button.
     */
    protected class DimmableButtonBackgroundDrawable extends LayerDrawable {

        // The color filter to apply when the button is pressed
        protected ColorFilter _pressedFilter = new LightingColorFilter(Color.LTGRAY, 1);
        // Alpha value when the button is disabled
        protected int _disabledAlpha = 100;
        // Alpha value when the button is enabled
        protected int _fullAlpha = 255;

        public DimmableButtonBackgroundDrawable(Drawable d) {
            super(new Drawable[] { d });
        }

        @Override
        protected boolean onStateChange(int[] states) {
            boolean enabled = false;
            boolean pressed = false;

            for (int state : states) {
                if (state == android.R.attr.state_enabled)
                    enabled = true;
                else if (state == android.R.attr.state_pressed)
                    pressed = true;
            }

            mutate();
            if (enabled && pressed) {
                setColorFilter(_pressedFilter);
            } else if (!enabled) {
                setColorFilter(null);
                setAlpha(_disabledAlpha);
            } else {
                setColorFilter(null);
                setAlpha(_fullAlpha);
            }

            invalidateSelf();

            return super.onStateChange(states);
        }

        @Override
        public boolean isStateful() {
            return true;
        }
    }

}
Matthew Cawley
źródło
0

wartości \ styles.xml

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>

<style name="RedAccentButton" parent="ThemeOverlay.AppCompat.Light">
    <item name="colorAccent">#ff0000</item>
</style>

następnie:

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

<Button
    style="@style/Widget.AppCompat.Button.Colored"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:enabled="false"
    android:text="text" />

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

<Button
    style="@style/Widget.AppCompat.Button.Colored"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:enabled="false"
    android:text="text"
    android:theme="@style/RedAccentButton" />

wynik

Milan Hlinák
źródło
0

Zgodnie z wytycznymi dotyczącymi projektowania materiałów należy użyć stylu podobnego do poniższego kodu

<style name="MyButton" parent="Theme.AppCompat.Light>
    <item name="colorControlHighlight">#F36F21</item>
    <item name="colorControlHighlight">#FF8D00</item>
</style>

i w układzie dodaj tę właściwość do przycisku

    android:theme="@style/MyButton"
Shivam
źródło
0

To proste .. dodaj tę zależność do swojego projektu i utwórz przycisk z 1. Dowolnym kształtem 2. Dowolnym kolorem 3. Dowolną ramką 4. Z efektami materialnymi

https://github.com/manojbhadane/QButton

<com.manojbhadane.QButton
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="OK"
       app:qb_backgroundColor="@color/green"
       app:qb_radius="100"
       app:qb_strokeColor="@color/darkGreen"
       app:qb_strokeWidth="5" />
Manoj Bhadane
źródło