BackgroundTint Lollipop не влияет на кнопку

83

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

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

К сожалению, это не действует, кнопка остается серой.

Я пробовал разные значения для backgroundTintMode, ничего не изменилось.

Я также пробовал делать это программно в своем Activity, что ничего не изменило.

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

Почему игнорируется мой оттенок?

РЕДАКТИРОВАТЬ: Чтобы уточнить, я действительно тестирую устройство Lollipop. Другие виджеты (например, EditText) правильно и автоматически окрашиваются.

Совет директоров
источник
3
Это ошибка, которая была исправлена ​​в будущем выпуске, но принятое решение будет работать с API 21+.
alanv 04
проверьте этот обновленный ответ
Амит Вагела

Ответы:

18

Протестировано на API 19 - 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" />

производит вывод как -

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

Сахитья Паснор
источник
Пометить это как принятый ответ, потому что через несколько лет я считаю, что теперь это официальный (и лучший) способ сделать это. (Незначительная деталь: я почти уверен, что в большинстве случаев вы можете просто использовать Button вместо AppCompatButton, и он все равно будет работать).
Совет директоров
118

Плохие новости

Как говорит BoD, тонировать фон кнопки в Lollipop 5.0 (уровень API 21) бессмысленно.

Хорошие новости

Lollipop 5.1 (уровень API 22), похоже, исправил это, изменив btn_mtrl_default_shape.xml (среди других файлов): https://android.googlesource.com/platform/frameworks/base/+/6dfa60f33ca6018959ebff1efde82db7d2aed1e3%5E!

Отличные новости

Новая библиотека поддержки (версия 22.1+) добавляет обратно совместимую поддержку тонирования для множества компонентов, включая AppCompatButton !

К сожалению, android:backgroundTintсвойство по-прежнему не работает (возможно, я что-то делаю не так), поэтому вам нужно установить ColorStateListкод, используя setSupportBackgroundTintList(). Было бы здорово увидеть android:backgroundTintподдержку в будущем. Обновление : Марсио Гранзотто прокомментировал, что app:backgroundTintработает с AppCompatButton! Обратите внимание, что это app:не так android:, потому что он находится в приложении / библиотеке.

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

Если вы позволите ему наследовать, ваша активность будет автоматически увеличиваться AppCompatButtonвместо обычного .ButtonAppCompatActivity

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

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

О, и не забудьте основать тему своего приложения на одной из Theme.AppCompatтем, иначе совместные просмотры будут очень и очень грустными ...;)

Это работало как на 2.3.7 (Gingerbread MR1), так и на 5.0 (Lollipop 'Classic').

Снильд Долкоу
источник
1
Просто добавил дополнительную информацию - что наиболее важно, теперь можно добиться тонирования кнопок с помощью новой версии (22.1) библиотеки поддержки, которая была выпущена на днях!
Snild Dolkow
8
Можно использовать colorButtonNormalс AppCompat 22.1.1 (установка темы только для кнопок), у меня работает на 4.4.4 и 5.1.
hunyadym
2
Есть идеи, как установить то же самое для TextView?
разработчик Android
8
Вместо этого new ColorStateList(new int[][]{new int[0]}, new int[]{0xffffcc00});можно писать более кратко ColorStateList.valueOf(0xffffcc00);.
Ашкан Сарлак
5
Вы можете использовать android.support.v7.widget.AppCompatButton с app: backgroundTint в xml
Марсио Гранзотто,
30

Кажется, что подкрашивание волнистого рисунка бессмысленно (а фон кнопки по умолчанию - волнистый).

Фактически, посмотрев на кнопку платформы по умолчанию, которую можно рисовать, я нашел «правильный» способ сделать это: Вы должны определить это в своей теме:

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

(Конечно, это только для уровня 21+.)

Предупреждение: поскольку это определено в теме, будет использоваться заданный цвет для всех кнопок (по крайней мере, для всех кнопок в действиях, использующих эту тему).

В качестве бонуса вы также можете изменить цвет ряби, указав это:

    <item name="android:colorControlHighlight">@color/accent_ripple</item>
Совет директоров
источник
colorControlHighlightоднако изменил бы множество других виджетов. Рад, что ты с этим справился.
natario 02
5
Вы можете применить это к отдельному представлению, определив тему наложения (например, без родительской темы и определив только один атрибут) и используя атрибут android: theme.
alanv 04
1
Тогда как это исправить для API 22 и выше? Также эта «ошибка» возникает только на некоторых устройствах API 21 (включая nexus 5, galaxy s3)
Ведант
22

Чтобы решить проблемы, связанные с тонировкой на Android 5.0.x, я использую что-то вроде этого:

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

Он использует метод поддержки только для API 21 и ViewCompat для всех остальных случаев.

GUG
источник
@Marco Use:if (view instanceof TintableBackgroundView) { ((TintableBackgroundView) view).setSupportBackgroundTintList(tint); } else { ViewCompat.setBackgroundTintList(view, tint); }
chessdork 01
Это не работает с ImageButton на устройствах pre lollipop.
toobsco42
Я получаю предупреждение о линте при использовании AppCompatButton.setSupportBackgroundTintList () AppCompatButton.setSupportBackgroundTintList можно вызывать только из той же группы библиотек (groupId = com.android.support)
starkej2
У меня это сработало, но мне пришлось поменять условия.
Родриго Венансио
«может вызываться только из одной группы библиотек (groupId = com.android.support», почему это предупреждение?
Ферран Негре
22

Обычно я делаю это динамически, используя PorterDuff:

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

Вы можете проверить различные режимы наложения здесь и хорошие примеры здесь .

Карлос Борау
источник
1
Я использовал PorterDuff.Mode.SRC, и он отлично работает
francisco_ssb
Прекрасно работает. В моем случае я хотел использовать эффект тонирования на API 17, это мне помогло.
ashishdhiman2007
2
Это должен быть принятый ответ. Подтвердите работу над API 20.
Hardanger
19

Просто используйте app:backgroundTintвместо android:backgroundTint, оттенок под Lollipop вступит в силу. Причина в том , AppCompatActivityиспользовать AppCompatViewInflaterдля кнопки автоматического изменения или TextView к AppCompatButton или AppCompatTextView, затем app:backgroundTintвступают в силу.

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

В своем проекте я его использовал, это сработало.

селезень
источник
9

Я думаю, тебе нужно было android:backgroundсделатьandroid:backgroundTint работе.

Чтобы быть более точным, я предполагаю, что вы не можете backgroundTintиспользовать фон кнопки по умолчанию из тем материалов, который определяется как файл RippleDrawable.

Натарио
источник
1
Думаю, вы правы. Фактически я нашел «правильный» способ делать то, что хочу (см. Мой ответ).
Совет директоров
3

О подобной проблеме сообщалось в google https://code.google.com/p/android/issues/detail?id=201873.

Но после выпуска библиотеки поддержки Android версии 23.2.1 (март 2016 г.) эта ошибка устранена.

Проблема: FloatingActionButton.setBackgroundTintList (оттенок @Nullable ColorStateList) больше не меняет цвет фона

обновить библиотеку поддержки до Android Support Library to 23.2.1

Используйте библиотеку поддержки дизайна (23.2.1) и appcompatwidgets, как показано ниже.

Материальный дизайн для устройств Pre-Lollipop :

AppCompat (он же ActionBarCompat) начинался как бэкпорт API ActionBar Android 4.0 для устройств, работающих на Gingerbread, предоставляя общий уровень API поверх реализованной реализации и реализации фреймворка. AppCompat v21 предоставляет API и набор функций, актуальный для Android 5.0.


Библиотека поддержки Android 22.1 :

Возможность автоматически подкрашивать виджеты при использовании AppCompat невероятно полезна для сохранения сильного брендинга и единообразия всего вашего приложения. Это делается автоматически при накачивании макетов - замена Button на AppCompatButton, TextView на AppCompatTextView и т. Д., Чтобы гарантировать, что каждый из них может поддерживать тонировку. В этом выпуске эти виджеты с поддержкой оттенков теперь общедоступны, что позволяет сохранить поддержку тонирования, даже если вам нужно создать подкласс одного из поддерживаемых виджетов.

Амит Вагела
источник
3

Просто используйте app: backgroundTint вместо android: backgroundTint

Смирнов Сергей
источник
2

Если мы посмотрим на исходный код библиотеки поддержки, мы увидим, что он обычно окрашивает известные кнопки, но если мы изменим форму нашей кнопки (у меня круглая кнопка), оттенок не будет работать нормально в api <= 21. Мы также можем видеть, что TintManager стал общедоступным классом (appcompat-v7: 23.1.1), поэтому мы можем взять ColorStateList из формы кнопки по умолчанию (которая хорошо окрашена в 5.0) для текущей темы (поэтому нам не нужно создавать массив цветов):

    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);
        }
Павел Бирюков
источник
начиная с appcompat 23.2, они изменили класс (хотя и публичный!) TintManager -> AppCompatDrawableManager, код остался почти таким же
Павел Бирюков
WTF ... getTintList теперь изменен с общедоступного на защищенный; (нужно использовать отражение :)
Павел Бирюков
0

Поскольку атрибут backgroundTintиспользуется только в API уровня 21 и выше

Fedache
источник
Я понимаю это, и я действительно тестирую устройство Lollipop. Я обновлю вопрос, чтобы прояснить это.
Совет директоров
0

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

Эта команда

  sendBtnView.setBackgroundTintList(colorState)

работал отлично в прошлом, но перестал работать на меня. после исследования выясняется, что причиной является библиотека, которая была добавлена ​​к зависимостям Gradle:

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

Поэтому я попытался изменить его на 23.02.1, как это было рекомендовано здесь, в сообщении Амита Вагелы. Я изменился на

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

Но ошибка gradle говорит, что у recyclerview lib нет этой версии (23.02.1) (gradle не смог найти ее в Jcenter raw.github или репо).

Затем, поскольку я знал, что команда setBackgroundTintList в прошлом хорошо работала с версией 22.02.0 'во всех других библиотеках, которые у меня есть в зависимостях Gradle. поэтому я меняю его на:

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

И теперь снова работает.

Уди Решеф
источник
0

Я не уверен, рекомендуется ли это, но вы можете попробовать следующее:

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

В общем, работает. Пытался, ViewCompatно, похоже, не работает.

Sud007
источник
0

вы можете использовать backgroundTint <android.support.design.button.MaterialButtonс "com.android.support:design:28.0.0-rc01"версией

Зафер Джелалоглу
источник
0

Если вы используете androidx, то добавление как с префиксом, так и без префикса версии решает проблему на 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>

Селектор button_primary находится в colorпапке со следующим содержимым:

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

и примените его к обычной кнопке на AppCompatActivity

<Button style="@style/Button_Primary"/>
Хитрый
источник