Как использовать селектор для оттенка imageview в android

Я хочу подкрасить значки моего tabhost с помощью xml, а не делать это программно (я все равно не смог этого сделать)... Поэтому я нашел эту тему на SO:Android imageview изменить оттенок для имитации нажмите кнопку

это кажется довольно хорошим решением, но я не смог правильно адаптировать его в своем проекте... Я сделал следующие изменения:

public class TintableImageView extends ImageView {
private ColorStateList tint;

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

//this is the constructor that causes the exception
public TintableImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context, attrs, 0);
}

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

//here, obtainStyledAttributes was asking for an array
private void init(Context context, AttributeSet attrs, int defStyle) {
    TypedArray a = context.obtainStyledAttributes(attrs, new int[]{R.styleable.TintableImageView_tint}, defStyle, 0);
    tint = a.getColorStateList(R.styleable.TintableImageView_tint);
    a.recycle();
}

@Override
protected void drawableStateChanged() {
    super.drawableStateChanged();
    if (tint != null && tint.isStateful())
        updateTintColor();
}

public void setColorFilter(ColorStateList tint) {
    this.tint = tint;
    super.setColorFilter(tint.getColorForState(getDrawableState(), 0));
}

private void updateTintColor() {
    int color = tint.getColorForState(getDrawableState(), 0);
    setColorFilter(color);
}

}

Я также не смог ссылаться @drawable/selector.xml at android:tint, поэтому я сделал это в цвета.XML-код:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="azulPadrao">#2e7cb4</color>
<drawable name="tab_icon_selector">@drawable/tab_icon_selector</drawable>
</resources>

мой селектор:

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:tint="#007AFF" />
<item android:state_focused="true" android:tint="#007AFF" />
<item android:state_pressed="true" android:tint="#007AFF" />
<item android:tint="#929292" />
</selector>

мой вкладке "макет":

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical" android:id="@+id/TabLayout"
          android:layout_width="fill_parent" android:layout_height="fill_parent"
          android:gravity="center" android:background="@drawable/tab_bg_selector">

<com.myapp.TintableImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/imageView" android:layout_gravity="center" android:tint="@drawable/tab_icon_selector"/>
<TextView android:id="@+id/TabTextView" android:text="Text"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content" android:textColor="@drawable/tab_text_selector"
          android:textSize="10dip"
          android:textStyle="bold" android:layout_marginTop="2dip"/>

</LinearLayout>

какие предложения? Заранее спасибо

[EDIT] я получал NumberFormatException использовать android:tint, когда правильнее было app:tint (после установки xmlns:app="http://schemas.android.com/apk/res/com.myapp")... но теперь я думаю, что неправильно использую селектор, потому что значки все черные, независимо от состояния... Я пробовал установить <drawable name="tab_icon_selector">@drawable/tab_icon_selector</drawable> из цветов.xml, не так ли работа

[/EDIT]

6 ответов


в отношении моего решения в https://stackoverflow.com/a/18724834/2136792, есть несколько вещей, которые вам не хватает:

TintableImageView.java

@Override
protected void drawableStateChanged() {
    super.drawableStateChanged();
    if (tint != null && tint.isStateful())
        updateTintColor();
}

public void setColorFilter(ColorStateList tint) {
    this.tint = tint;
    super.setColorFilter(tint.getColorForState(getDrawableState(), 0));
}

private void updateTintColor() {
    int color = tint.getColorForState(getDrawableState(), 0);
    setColorFilter(color);
}

drawableStateChanged () необходимо переопределить, чтобы оттенок обновлялся при изменении состояния элемента.

Я не уверен, что ссылка на drawable из drawable может вызвать проблему, но вы можете просто переместить селектор.XML в папку "/РЭС/цвет" в обратитесь к нему с помощью " @color / selector.xml " (aapt объединяет оба /res / значения / цвета.xml и папка/res / color).


Если вы находитесь в API 21+, Вы можете легко сделать это в XML с помощью селектора и подкраска:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_activated="true">
        <bitmap android:src="@drawable/ic_settings_grey"
                android:tint="@color/primary" />
    </item>

    <item android:drawable="@drawable/ic_settings_grey"/>
</selector>

я реализовал это с помощью DrawableCompat из библиотеки Android support-v4.

обычный ImageButton (который подклассы ImageView, так что эта информация также относится к ImageViews), используя черный значок из коллекция иконок материалов:

<ImageButton
  android:id="@+id/button_add"
  android:src="@drawable/ic_add_black_36dp"
  android:background="?attr/selectableItemBackgroundBorderless"
  android:contentDescription="@string/title_add_item" />

это метод утилиты, который я создал:

public static void tintButton(@NonNull ImageButton button) {
    ColorStateList colours = button.getResources()
            .getColorStateList(R.color.button_colour);
    Drawable d = DrawableCompat.wrap(button.getDrawable());
    DrawableCompat.setTintList(d, colours);
    button.setImageDrawable(d);
}

здесь res/color/button_colour.xml - селектор, который меняет цвет значка с красного на полупрозрачный красный, когда кнопка нажата:

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

    <item
      android:state_pressed="false"
      android:color="@color/red" />

    <item
      android:color="@color/red_alpha_50pc" />

</selector>

после ImageButton был раздут в моей деятельности onCreate() метод, я просто вызываю tintButton(...) вспомогательный метод для каждой кнопки.


я протестировал это на Android 4.1 (my minSdkVersion) и 5.0 устройств, но DrawableCompat должен вернуться к Android 1.6.


с библиотекой поддержки 22.1 мы можем использовать DrawableCompat для окрашивания drawable, уровень API 4+

DrawableCompat.wrap (Drawable) и setTint (), setTintList () и setTintMode () будут просто работать: нет необходимости создавать и поддерживать отдельные чертежи только для поддержки нескольких цветов!


Я согласен с @Dreaming в коде, и я приведу пример.

ic_up_small

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

    <item android:color="@color/comment_count_selected_color" android:state_selected="true" />
    <item android:color="@color/comment_count_text_color"/>

</selector>

layout / item_post_count_info.в XML

<android.support.v7.widget.AppCompatImageView
    android:id="@+id/post_upvote_icon"
    android:layout_width="14dp"
    android:layout_height="14dp"
    android:layout_marginLeft="17dp"
    app:srcCompat="@drawable/ic_up_small"
    app:tint="@color/post_up_color"/>

внимание: мы должны использовать app: оттенок вместо android: оттенок.

моя версия библиотеки поддержки-26.0.2.

app / build.Gradle в

implementation 'com.android.support:appcompat-v7:26.0.2'
implementation 'com.android.support:support-core-utils:26.0.2'
implementation 'com.android.support:support-annotations:26.0.2'
implementation 'com.android.support:support-v4:26.0.2'
implementation 'com.android.support:design:26.0.2'

Если мы используем android:tint, он рухнет, и журнал выглядит так:

E / AndroidRuntime: фатальное исключение: main андроид.вид.InflateException: двоичная строка XML-файла #0: ошибка класс надувания на Андроид.вид.LayoutInflater.createView(LayoutInflater.java: 613) на андроид.вид.LayoutInflater.createViewFromTag (LayoutInflater.java: 687) на Андроид.вид.LayoutInflater.rInflate (LayoutInflater.java: 746) на Андроид.вид.LayoutInflater.надуть(LayoutInflater.java: 489) на Андроид.вид.LayoutInflater.надуть(LayoutInflater.java: 396) на com.опера.шесть.viewholder.должность.PostCountInfoViewHolder$1.создать (PostCountInfoViewHolder.java: 29) на com.опера.шесть.viewholder.должность.PostCountInfoViewHolder$1.создать (PostCountInfoViewHolder.java: 25) на com.опера.шесть.коллекция.CollectionAdapter.onCreateViewHolder (CollectionAdapter.java: 39) на com.опера.шесть.коллекция.CollectionAdapter.onCreateViewHolder (CollectionAdapter.java: 19) на андроид.поддержка.В7.штучка.RecyclerView$Адаптер.createViewHolder (RecyclerView.java: 6493) на андроид.поддержка.В7.штучка.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline (RecyclerView.java: 5680) на андроид.поддержка.В7.штучка.RecyclerView$Recycler.getViewForPosition (RecyclerView.java: 5563) на андроид.поддержка.В7.штучка.RecyclerView$Recycler.getViewForPosition (RecyclerView.java: 5559) на андроид.поддержка.В7.штучка.LinearLayoutManager$LayoutState.далее (LinearLayoutManager.java: 2229) на андроид.поддержка.В7.штучка.LinearLayoutManager.layoutChunk (LinearLayoutManager.java: 1556) на андроид.поддержка.В7.штучка.LinearLayoutManager.заливка (LinearLayoutManager.java: 1516) на андроид.поддержка.В7.штучка.LinearLayoutManager.onLayoutChildren (LinearLayoutManager.java: 608) на андроид.поддержка.В7.штучка.RecyclerView.dispatchLayoutStep2 (RecyclerView.java: 3693) на андроид.поддержка.В7.штучка.RecyclerView.dispatchLayout (RecyclerView.java: 3410) на андроид.поддержка.В7.штучка.RecyclerView.onLayout (RecyclerView.java: 3962) на андроид.вид.Вид.режим разметки.java: 13754) на Андроид.вид.ViewGroup.макет(ViewGroup.java: 4364) на андроид.поддержка.В4.штучка.SwipeRefreshLayout.onLayout (SwipeRefreshLayout.java: 610) на Андроид.вид.Вид.режим разметки.java: 13754) на Андроид.вид.ViewGroup.макет(ViewGroup.java: 4364) на андроид.поддержка.дизайн.штучка.HeaderScrollingViewBehavior.layoutChild (HeaderScrollingViewBehavior.java: 132) на андроид.поддержка.дизайн.штучка.ViewOffsetBehavior.onLayoutChild (ViewOffsetBehavior.java: 42) на андроид.поддержка.дизайн.штучка.AppBarLayout$ScrollingViewBehavior.onLayoutChild (AppBarLayout.java: 1361) на андроид.поддержка.дизайн.штучка.CoordinatorLayout.метода onlayout(CoordinatorLayout.java: 869) на Андроид.вид.Вид.режим разметки.java: 13754) на андроид.вид.ViewGroup.макет(ViewGroup.java: 4364) на Андроид.поддержка.В4.вид.ViewPager.метода onlayout(ViewPager.java: 1767) на Андроид.вид.Вид.режим разметки.java: 13754) на Андроид.вид.ViewGroup.макет(ViewGroup.java: 4364) на Андроид.штучка.LinearLayout.setChildFrame (LinearLayout.java: 1649) на Андроид.штучка.LinearLayout.layoutVertical (LinearLayout.java: 1507) на Андроид.штучка.LinearLayout.onLayout (LinearLayout.java: 1420) на Андроид.вид.Вид.режим разметки.java: 13754) на Андроид.вид.ViewGroup.макет(ViewGroup.java: 4364) на Андроид.штучка.Так.onLayout (FrameLayout.java: 448) на Андроид.вид.Вид.режим разметки.java: 13754) на Андроид.вид.ViewGroup.макет(ViewGroup.java: 4364) на Андроид.штучка.Так.onLayout (FrameLayout.java: 448) на Андроид.вид.Вид.режим разметки.java: 13754) на Андроид.вид.ViewGroup.макет(ViewGroup.java: 4364) на Андроид.штучка.LinearLayout.setChildFrame (LinearLayout.java: 1649) на Андроид.штучка.LinearLayout.layoutVertical (LinearLayout.java: 1507) на Андроид.штучка.LinearLayout.onLayout (LinearLayout.java: 1420) на Андроид.вид.Вид.режим разметки.java: 13754) на андроид.вид.ViewGroup.макет(ViewGroup.java: 4364) на Андроид.штучка.Так.onLayout (FrameLayout.java: 448) на Андроид.вид.Вид.режим разметки.java: 13754) на Андроид.вид.ViewGroup.макет(ViewGroup.java: 4364) на Андроид.штучка.Так.onLayout (FrameLayout.java: 448) на Андроид.вид.Вид.режим разметки.java: 13754) на Андроид.вид.ViewGroup.макет(Ви


С текущей библиотекой поддержки AppCompat вы можете использовать app:tint on ImageView бирка которая будет надута как AppCompatImageView и обрабатывать изменение состояния правильно.

на AppCompatImageView видно, что mImageHelper уведомляется об изменении состояния:

@Override
protected void drawableStateChanged() {
    super.drawableStateChanged();
    if (mBackgroundTintHelper != null) {
        mBackgroundTintHelper.applySupportBackgroundTint();
    }
    if (mImageHelper != null) {
        mImageHelper.applySupportImageTint();
    }
}

Android Studio в настоящее время дает предупреждение об этом, но вы можете безопасно подавить его.