Как использовать селектор для оттенка 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
, так что эта информация также относится к ImageView
s), используя черный значок из коллекция иконок материалов:
<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 в настоящее время дает предупреждение об этом, но вы можете безопасно подавить его.