Оттенок TextView на AppCompat

Я сделал несколько флажков и переключателей с текстовыми представлениями, но они не окрашены перед леденцом на палочке.

Мои текстовые представления расширяются AppCompatCheckedTextView, в стиле:

<style name="CheckBoxStyle" parent="android:Widget.TextView">
    <item name="android:textAppearance">?android:attr/textAppearance</item>
    <item name="android:drawableRight">?android:attr/listChoiceIndicatorMultiple</item>
    <item name="android:drawableEnd">?android:attr/listChoiceIndicatorMultiple</item>
    <item name="android:clickable">true</item>
    <item name="android:background">?attr/selectableItemBackground</item>
    <item name="android:gravity">center_vertical</item>
    <item name="android:paddingTop">8dp</item>
    <item name="android:paddingBottom">8dp</item>
</style>

и мой акцент определен в моей теме:

<style name="AppTheme.Platform.NoActionBar" parent="Theme.AppCompat.NoActionBar">
    <item name="android:selectableItemBackground">@drawable/press_overlay_dark</item>
    <item name="android:borderlessButtonStyle">@style/BorderlessButton</item>

    <item name="android:colorAccent">@color/color_accent</item>
    <item name="colorAccent">@color/color_accent</item>
</style>

Я строю против v21, с минимумом v16 и использую AppCompat v7-22.1.1. Моя деятельность расширяет AppCompatActivity

Genymotion 4.1.1Nexus 5 5.1.1

5 ответов

Решение

Глядя на источник для AppCompatCheckedTextView Я наконец понял это. Это только подкрашивает checkMark, Так как это происходит из CheckedTextView который вытекает из TextView, drawableRight только тонируется на леденце. Глядя на источник для AppCompatTextView, он обеспечивает только обратную совместимость textAllCaps, Так что AFAIK, нет встроенного способа подкрасить drawableRight и тому подобное перед леденцом на палочке. Если вы хотите более настраиваемое решение, вам может понадобиться разместить свои чертежи в макете.

Обновленный стиль:

<style name="CheckBoxStyle" parent="android:Widget.TextView">
    <item name="android:textAppearance">@style/TextAppearance.AppCompat</item>
    <item name="android:checkMark">?android:attr/listChoiceIndicatorSingle</item>
    <item name="android:clickable">true</item>
    <item name="android:background">?attr/selectableItemBackground</item>
    <item name="android:gravity">center_vertical</item>
    <item name="android:paddingTop">8dp</item>
    <item name="android:paddingBottom">8dp</item>
</style>

Для уровня API 23 >= android:drawableTint="@color/colorPrimary"

Для уровня Api <уровень Api 23:

private void setTextViewDrawableColor(TextView textView, int color) {
        for (Drawable drawable : textView.getCompoundDrawables()) {
            if (drawable != null) {
                drawable.setColorFilter(new PorterDuffColorFilter(getColor(color), PorterDuff.Mode.SRC_IN));
            }
        }
    }

Для API 23 и выше, просто установите его в макете: android:drawableTint="@color/custom_color"

Если вам нужна обратная совместимость, вам нужно будет установить ее программно. В Kotlin вы можете создать функцию расширения, например:

fun TextView.setDrawableColor(@ColorRes color: Int) {
    compoundDrawables.filterNotNull().forEach {
        it.colorFilter = PorterDuffColorFilter(getColor(context, color), PorterDuff.Mode.SRC_IN)
    }
}

И используйте это как: textView.setDrawableColor(R.color.custom_color)

Обратите внимание, что filterNotNull() здесь очень важно, поскольку список элементов для рисования, скорее всего, будет иметь некоторые нулевые значения (для всех элементов рисования в TextView, которые не были установлены).

Не прямой ответ на решение. Однако, если вы используете привязку данных и хотите добавить оттенок для рисования. Проверьте следующий пример: протестировано на последних версиях, но также должно работать на Api <=21

  @JvmStatic
    @BindingAdapter(value = ["app:drawableStart", "app:drawableStartTint"], requireAll = true)
    fun setDrawableStartTint(textView: TextView, @DrawableRes drawable: Drawable, @ColorInt color: Int) {
        val mutatedDrawable = drawable.mutate()
        mutatedDrawable.setColorFilter(color, PorterDuff.Mode.MULTIPLY)
        textView.setCompoundDrawablesWithIntrinsicBounds(mutatedDrawable, null, null, null)
    }

Использование:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello World"
    app:drawableStart="@{@drawable/ic_demo}"
    app:drawableStartTint="@{@color/color_demo_tint}"
 />

Вот обратно совместимый TextView.

Использование:

<com.github.mrezanasirloo.TextViewCompatTint
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:drawableStart="@drawable/ic_comment_black_14dp"
    app:drawableTint="@color/colorPrimary"
    tools:text="28"
    />

суть

Тонировка виджета в AppCompat работает путем перехвата любой разметки макета и вставки на его место специальной версии виджета, учитывающей оттенки. Если у вас есть собственная настраиваемая версия виджета, которая в вашем случае - проверенный текстовый вид, тонировка не будет работать

От блога разработчиков под тонировку виджета

http://android-developers.blogspot.com/2014/10/appcompat-v21-material-design-for-pre.html

При работе на устройствах с Android 5.0 все виджеты окрашиваются с использованием атрибутов цветовой темы, о которых мы только что говорили. В Lollipop есть две основные функции, которые позволяют это: рисовать подкрашиванием и ссылаться на атрибуты темы (в форме? Attr / foo) в отрисовках.

AppCompat обеспечивает аналогичное поведение в более ранних версиях Android для подмножества виджетов пользовательского интерфейса:

Все, что предусмотрено панелью инструментов AppCompat (режимы действий и т. Д.)

Редактировать текст

волчок

CheckBox

Переключатель

Переключатель (используйте новый android.support.v7.widget.SwitchCompat)

CheckedTextView

Вам не нужно делать ничего особенного, чтобы заставить их работать, просто используйте эти элементы управления в ваших макетах, как обычно, и AppCompat сделает все остальное (с некоторыми оговорками; см. FAQ ниже).

У меня проблема с оттенком. AppCompatTextView не имеет эффекта оттенка при работе на SDK ниже 21. Мое решение - установить цвет оттенка через Java. Пример ниже работает.

XML

    <android.support.v7.widget.AppCompatTextView
    android:layout_width="50dp"
    android:layout_height="20dp"
    android:id="@+id/tvInfor2"
    android:background="@drawable/btn_style_black_border"
    android:gravity="center"
    android:backgroundTint="@color/colorPrimary"/>

Джава

    int currentapiVersion = android.os.Build.VERSION.SDK_INT;
    if (currentapiVersion <= 21){
        tvInfor2.setSupportBackgroundTintList(getResources().getColorStateList(R.color.colorPrimary));
    }

В котлин:

fun TextView.setDrawableTintColor(colorRes: Int) {
  for (drawable in this.compoundDrawablesRelative) {
    drawable?.colorFilter = PorterDuffColorFilter(getColor(context, colorRes), PorterDuff.Mode.SRC_IN)
  }
}

Использование:

myTextView.setDrawableTintColor(R.color.colorPrimary)

Упрощая верхний ответ, это будет расширение в Котлине (но я не проверял):

fun TextView.setDrawableColor(@ColorRes color: Int) {
    val colorFilter = PorterDuffColorFilter(getColor(context, color), PorterDuff.Mode.SRC_IN)
    compoundDrawables.filterNotNull().forEach {
        it.colorFilter = colorFilter
    }
}

Среди всех решений, которые у меня не работают, я создал следующие:

JAVA: совместимый Api < 23

private void setTextViewDrawableColor(@RecentlyNonNull TextView textView,@ColorRes int color) {
        for (Drawable drawable : textView.getCompoundDrawablesRelative()) {
            if (drawable != null) {
                drawable.setColorFilter(new PorterDuffColorFilter(ContextCompat.getColor(textView.getContext(),color), PorterDuff.Mode.SRC_IN));
            }
        }
    }

Использовать

setTextViewDrawableColor(textView1,R.color.AccentColor)

КОТЛИН

private fun setTextViewDrawableColor(@NonNull textView: TextView, @ColorRes color: Int) {
    for (drawable in textView.compoundDrawablesRelative) {
        if (drawable != null) {
            drawable.colorFilter = PorterDuffColorFilter(ContextCompat.getColor(textView.context, color), PorterDuff.Mode.SRC_IN)
        }
    }
}

Использовать

setTextViewDrawableColor(textView1,R.color.AccentColor)

КОТЛИНСКОЕ РАСШИРЕНИЕ

fun TextView.setDrawableColor(@ColorRes color: Int) {
    compoundDrawablesRelative.filterNotNull().forEach {
        it.colorFilter = PorterDuffColorFilter(ContextCompat.getColor(this.context, color), PorterDuff.Mode.SRC_IN)
    }
}

использовать

textView1.setDrawableColor(R.color.colorAccent)

ТОЛЬКО XML API => 23

android:backgroundTintMode="src_in"
android:drawableTint="FF0000"
Другие вопросы по тегам