Стандартная кнопка Android с другим цветом


735

Я бы хотел немного изменить цвет стандартной кнопки Android, чтобы лучше соответствовать брендингу клиента.

Наилучший способ, который я нашел для этого, - это поменять Buttonобъект рисования на рисунок, расположенный в 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>

Но для этого требуется, чтобы я фактически создал три разных рисования для каждой кнопки, которую я хочу настроить (один для кнопки в состоянии покоя, один для фокусировки и один для нажатия). Это кажется более сложным и не СУХИМ, чем мне нужно.

Все, что я действительно хочу сделать, это применить какое-то цветовое преобразование к кнопке. Есть ли более простой способ изменить цвет кнопки, чем я?


Ответы:


724

Я обнаружил, что все это можно сделать одним файлом довольно легко. Поместите что-то вроде следующего кода в файл с именем, custom_button.xmlа затем установите background="@drawable/custom_button"в виде кнопок:

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

43
Это хорошо работает с цветом фона - вы можете установить цвет текста таким же образом?
Рейчел

8
Это дает мне "Error: No resource found that matches the given name (at 'color' with value '@color/yellow1')" эти ссылки на встроенные цвета? кажется, мне нужен res / values ​​/ color.xml, чтобы сделать эту работу
Гарри Вуд

8
@HarryWood вы должны определить эти цвета в вашем res / values ​​/ colors.xml. Либо замените их на «# ff0000», «# 00ff00», для целей тестирования @ cfarm54 Этот файл должен быть помещен в папку res / drawable / custom_button.xml @emmby. Спасибо за фрагмент кода!
espinchi

17
Отличный указатель, спасибо! Также обратите внимание, что для других людей, пробующих это, порядок элементов в селекторе имеет большое значение. Если вы сначала поместите <item> без фильтров состояния в файл, он переопределит остальные.
mikerowehl

9
чтобы сделать это, поместите custom_button.xml в папку res / "drawable" - и создайте файл res / values ​​/ colors.xml со следующим содержимым: stackoverflow.com/questions/3738886/… - измените имена цветов в любом файле чтобы заставить его работать
Сами

308

Следуя ответу Томаша, вы также можете программно установить оттенок всей кнопки, используя режим умножения PorterDuff. Это изменит цвет кнопки, а не только оттенок.

Если вы начинаете со стандартной серой затененной кнопки:

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

даст вам красную затененную кнопку,

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

даст вам зеленую кнопку и т.д., где первое значение - это цвет в шестнадцатеричном формате.

Это работает путем умножения текущего значения цвета кнопки на ваше значение цвета. Я уверен, что с этими режимами можно сделать гораздо больше.


2
Ничего себе, только что попробовал это, и это просто фантастика. Спасибо! Вы случайно не знаете, есть ли способ сделать это через xml?
Эмбби

4
Ребята, проверьте это на HTC Desire! У них разные стандартные кнопки. Мои кнопки, использующие этот код, выглядят там прекрасно при установке определенной layout_width, например, «40dp». С "wrap_content" это нормально.
OneWorld,

5
Подтверждено, что это решение не очень хорошо работает в пользовательском интерфейсе HTC Sense
emmby 21.10.10

19
Затмение не показывает это как возможное исправление:import android.graphics.PorterDuff;
Кто-то где-то

2
У кого-нибудь были проблемы с этим не работающим в ICS? Кажется, он не работает на эмуляторе или телефоне для меня ..
Stev_k

149

Майк, тебя могут заинтересовать цветовые фильтры.

Пример:

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

попробуйте это, чтобы получить цвет, который вы хотите.


Попробуйте передать значение null в методе setColorFilter. Не пробовал, но это должно сработать.
Томаш

6
@Pacerier to unset: button.getBackground (). ClearColorFilter ();
Стэн Курджиль

3
Я рекомендую выбирать цвет, используя класс Color: developer.android.com/reference/android/graphics/Color.html
Mugen

Идеально подходит для темных тем! Я предполагаю, что другой верхний ответ (setColorFilter (0xFFFF0000, PorterDuff.Mode.MULTIPLY)) лучше работает для светлых тем.
java.is.for.desktop

85

Это мое решение, которое отлично работает, начиная с API 15 . Это решение сохраняет все эффекты нажатия кнопок по умолчанию, такие как материалRippleEffect . Я не тестировал его на более низких API, но он должен работать.

Все, что вам нужно сделать, это:

1) Создайте стиль, который меняется только colorAccent:

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

Я рекомендую использовать ThemeOverlay.AppCompatили ваш основной AppThemeкак родительский, чтобы сохранить остальные ваши стили.

2) Добавьте эти две строки в ваш buttonвиджет:

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

Иногда ваш новый colorAccentне отображается в Android Studio Preview, но при запуске приложения на телефоне цвет будет изменен.


Пример кнопки виджета

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

Кнопка образца с пользовательским цветом


1
Что делает эта строка? "style =" @ style / Widget.AppCompat.Button.Colored ""
Чарльз Ли

2
Это помогло мне понять разницу между стилем и темой. Спасибо.
rpattabi

2
Принятый ответ правильный, но слишком старый. Это простой и самый актуальный ответ.
正宗 白 布鞋

Проблема с этим ответом заключается в том, что настройка colorAccentвлияет не только на фон кнопки.
Blcknx

@Blcknx Что например?
RediOne1

61

Теперь Вы можете также использовать AppCompat-V7 в AppCompatButton с backgroundTintатрибутом:

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

4
У меня не сработало использование пространства имен "android:". Но это сработало, когда я вместо этого использовал пространство имен app:.
Дэвид Веласкес

@DavidVelasquez Это сработало и для меня на Android Lollipop, в то время как пространство имен android: ничего не изменило. Спасибо за помощь!
Авинаш Прабхакар

Это самое простое решение и должно быть принятым ответом. Использование android: backgroundTint у меня работает.
Рамашиш Баранвал

1
Должно быть app:backgroundTintвместо android:backgroundTintиспользования AppCompat.
Хафез Дивандари

23

Мне нравится предложение цветового фильтра в предыдущих ответах от @conjugatedirection и @Tomasz; Однако я обнаружил, что предоставленный код не так легко применяется, как я ожидал.

Во-первых, не было указано, где применять и очищать цветной фильтр. Возможно, есть и другие хорошие места для этого, но то, что мне пришло в голову, это OnTouchListener .

Из моего прочтения исходного вопроса, идеальным решением было бы то, которое не включает никаких изображений. Принятый ответ с использованием custom_button.xml от @emmby, вероятно, лучше подходит, чем цветовые фильтры, если это ваша цель. В моем случае я начинаю с png-изображения от дизайнера пользовательского интерфейса того, как должна выглядеть кнопка. Если я установлю фон кнопки на это изображение, обратная связь по умолчанию будет полностью потеряна. Этот код заменяет это поведение программным эффектом затемнения.

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();
    }
});

Я извлек это как отдельный класс для приложения к нескольким кнопкам - показанный как анонимный внутренний класс, чтобы понять идею.


Это было отличное решение! В основном это то же самое, что и на iOS по умолчанию, что нравится дизайнерам :-)
Кристер Нордвик,

Я попробовал это с 2 кнопками на том же экране с тем же фоном, и эффект применяется к обеим кнопкам на Touch
Goofy

16

Если вы создаете цветные кнопки с помощью XML, вы можете сделать код немного чище, указав сфокусированное и нажатое состояние в отдельном файле и повторно их использовать. Моя зеленая кнопка выглядит так:

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

1
отлично. как заставить сфокусированное и нажатое состояние вернуться к стандартным определениям Android для кнопок?
larham1

Я уверен, что вы этого не делаете, поскольку стандартные кнопки Android реализованы в виде растровых изображений с 9 патчами.
Haemish

12

Самое короткое решение, которое работает с любой версией Android:

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

Примечания / Требования :

  • Используйте app:пространство имен и неandroid: пространство имен!
  • версия приложения> 24.2.0

    dependencies {compile 'com.android.support:appcompat-v7:25.3.1'}

Пояснение : введите описание изображения здесь


1
Интересно, что у меня app:backgroundTint="@color/my_color"не получилось. android:backgroundTint="@color/my_color"работал отлично, хотя.
Игорь

Это самое короткое и чистое решение для меня и все.
Марти

11

Я использую этот подход

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>

Как вы можете видеть сверху, я использую собственный стиль для моей кнопки. Цвет кнопки соответствует цвету акцента. Я считаю, что это гораздо лучший подход, чем настройка, так android:backgroundкак я не потеряю волновой эффект, который обеспечивает Google.


8

Теперь есть гораздо более простой способ: android-holo-colors.com

Это позволит вам легко менять цвета всех голографических рисунков (кнопок, блесен, ...). Вы выбираете цвет, а затем загружаете ZIP-файл, содержащий рисунки для всех разрешений.


8

Используйте это таким образом:

buttonOBJ.getBackground().setColorFilter(Color.parseColor("#YOUR_HEX_COLOR_CODE"), PorterDuff.Mode.MULTIPLY);

4

В <Button>использовании android:background="#33b5e5". или лучшеandroid:background="@color/navig_button"


3

В библиотеке компонентов DroidUX есть ColorButtonвиджет, цвет которого можно легко изменять как с помощью определения xml, так и программно во время выполнения, так что вы даже можете позволить пользователю установить цвет / тему кнопки, если ваше приложение это позволяет.


3

Вы также можете использовать этот онлайн-инструмент для настройки своей кнопки http://angrytools.com/android/button/ и использовать ее android:background="@drawable/custom_btn"для определения настраиваемой кнопки в макете.


2

Вы можете установить тему вашей кнопки на это

<style name="AppTheme.ButtonBlue" parent="Widget.AppCompat.Button.Colored">
 <item name="colorButtonNormal">@color/HEXColor</item>
 <item name="android:textColor">@color/HEXColor</item>
</style>

1

Самый простой способ - просто определить пользовательский класс Button, который принимает все свойства, которые вам нужны, такие как радиус, градиент, цвет нажатия, нормальный цвет и т. Д., А затем просто использовать это в макетах XML вместо настройки фона с помощью XML. Образец здесь

Это очень полезно, если у вас много кнопок с такими же свойствами, как радиус, выбранный цвет и т. Д. Вы можете настроить свою унаследованную кнопку для обработки этих дополнительных свойств.

Результат (не использовался селектор фона).

Обычная кнопка

Нормальное изображение

Нажатая кнопка

введите описание изображения здесь


0

Способ, которым я делаю другую стилизованную кнопку, которая работает достаточно хорошо, - это создать подкласс объекта Button и применить цветовой фильтр. Это также обрабатывает включенные и отключенные состояния, применяя альфа к кнопке.

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

}

0

значения \ 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>

тогда:

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

результат


0

В соответствии с рекомендациями по дизайну материала, вы должны использовать стиль, как показано ниже

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

и в макете добавьте это свойство к вашей кнопке

    android:theme="@style/MyButton"

0

Это просто .. добавить эту зависимость в ваш проект и создать кнопку с 1. Любая форма 2. Любой цвет 3. Любая граница 4. С эффектами материала

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" />
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.