Comment utiliser selector pour teinter imageview dans android

je veux teinter les icônes de mon tabhost en utilisant xml, au lieu de le faire de façon programmatique (Je n'ai pas pu le faire de toute façon)... Donc, j'ai trouvé ce fil sur SO: Android imageview changer la teinte pour simuler bouton cliquez sur

cela semble être une très bonne solution, mais je n'ai pas pu l'adapter correctement dans mon projet... J'ai fait les changements suivants:

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

}

Je n'ai pas non plus pu faire référence à @drawable/selector.xml à android:tint , donc j'ai fait ça à colors.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>

mon sélecteur:

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

mise en page de mon onglet:

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

des suggestions? Merci d'avance

[EDIT] je recevais un NumberFormatException pour utiliser android:tint , alors que le correct était app:tint (après avoir mis xmlns:app="http://schemas.android.com/apk/res/com.myapp" )... mais maintenant je pense que j'utilise mon sélecteur d'une mauvaise manière, parce que les icônes sont toutes noires, peu importe le état... J'ai essayé de mettre <drawable name="tab_icon_selector">@drawable/tab_icon_selector</drawable> dans les couleurs.xml, n'a pas de travail

[/EDIT]

23
demandé sur Community 2013-10-21 20:36:24

6 réponses

en référence à ma solution à https://stackoverflow.com/a/18724834/2136792 , il y a quelques choses qui vous manquent:

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 () doit être remplacé pour que la teinte soit mise à jour lorsque l'état de l'élément change.

Je ne suis pas sûr que référencer un drawable à partir d'un drawable pourrait causer un problème, mais vous pouvez déplacez simplement votre sélecteur.xml dans un dossier "/res/couleur" de référence "@couleur/sélecteur.xml" (aapt fusionne les deux /res/valeurs/couleurs.xml et le dossier /res/color).

11
répondu Stephen Kidson 2017-05-23 12:34:59

si vous êtes dans API 21+ , vous pouvez le faire facilement en XML avec un sélecteur et teinte :

<?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>
25
répondu Christopher Perry 2015-02-05 20:58:04

j'ai implémenté ceci en utilisant DrawableCompat de la bibliothèque Android support-v4.

avec un régulier ImageButton (qui sous-classe ImageView , donc cette info s'applique aussi à ImageView s), en utilisant une icône noire de la collection d'icônes matérielles :

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

C'est la méthode utilitaire que j'ai créée:

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 est un sélecteur qui change la couleur de l'icône du rouge au rouge semi-transparent quand le bouton est appuyé:

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

après que le ImageButton a été gonflé dans la méthode de mon activité onCreate() , j'appelle juste la méthode d'aide tintButton(...) une fois pour chaque bouton.


j'ai testé cela sur Android 4.1 (mon minSdkVersion ) et 5.0 appareils, mais DrawableCompat devrait revenir à Android 1.6.

19
répondu Christopher Orr 2015-08-05 15:10:25

avec la bibliothèque de soutien 22.1 nous pouvons utiliser DrawableCompat pour teinter dessinable, niveau API 4 +

DrawableCompat.wrap (Drawable) et setTint (), setTintList (), et setTintMode () ne feront que fonctionner: pas besoin de créer et de maintenir des drawables séparés uniquement pour supporter plusieurs couleurs!

10
répondu wrecker 2015-04-22 06:59:07

je suis d'accord avec @Dreaming en Code et je vais donner un exemple.

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>

mise en page/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"/>

Attention:nous devrions utiliser app:teinte au lieu de android: teinte .

ma version de bibliothèque de soutien est 26.0.2.

application/build.Grad

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'

si nous utilisons android:teinte, il va se crasher et le log est comme ceci:

E/AndroidRuntime: FATAL EXCEPTION: main Android.vue.InflateException: binaire ligne de fichier XML no 0: erreur le gonflage de la classe au android.vue.LayoutInflater.createView (LayoutInflater.java: 613) à Android.vue.LayoutInflater.createViewFromTag (LayoutInflater.java: 687) au android.vue.LayoutInflater.rInflate (LayoutInflater.java: 746) au android.vue.LayoutInflater.gonfler(LayoutInflater.java: 489) au android.vue.LayoutInflater.gonfler(LayoutInflater.java: 396) à COM.Opéra.six.viewholder.post.PostCountInfoViewHolder$1.créer(PostCountInfoViewHolder.java: 29) à COM.Opéra.six.viewholder.post.PostCountInfoViewHolder$1.créer(PostCountInfoViewHolder.java: 25) à COM.Opéra.six.collection.CollectionAdapter.en ce qui concerne le nouveau support de collecte (CollectionAdapter.java: 39) à COM.Opéra.six.collection.CollectionAdapter.en ce qui concerne le nouveau support de collecte (CollectionAdapter.java: 19) à Android.soutien.v7.widget.RecyclerView $ Adaptateur.createViewHolder (RecyclerView.java: 6493) à Android.soutien.v7.widget.RecyclerView $ Recycler.trygetviewholder for position bydeadline (RecyclerView.java: 5680) à Android.soutien.v7.widget.RecyclerView $ Recycler.getViewForPosition (RecyclerView.java: 5563) à Android.soutien.v7.widget.RecyclerView $ Recycler.getViewForPosition (RecyclerView.java: 5559) à Android.soutien.v7.widget.LinearLayoutManager $ LayoutState.suivant (LinearLayoutManager.java: 2229) à Android.soutien.v7.widget.LinearLayoutManager.layoutChunk (LinearLayoutManager.java: 1556) à Android.soutien.v7.widget.LinearLayoutManager.fill (LinearLayoutManager.java: 1516) à Android.soutien.v7.widget.LinearLayoutManager.onlayoutenfants (LinearLayoutManager.java: 608) à Android.soutien.v7.widget.RecyclerView.dispatchLayoutStep2 (RecyclerView.java: 3693) à Android.soutien.v7.widget.RecyclerView.dispatchLayout (RecyclerView.java: 3410) à Android.soutien.v7.widget.RecyclerView.onLayout (RecyclerView.java: 3962) au android.vue.Vue.mise en page(à Vue.java: 13754) au android.vue.ViewGroup.mise en page(ViewGroup.java: 4364) à Android.soutien.v4.widget.SwipeRefreshLayout.onLayout (SwipeRefreshLayout.java: 610) au android.vue.Vue.mise en page(à Vue.java: 13754) au android.vue.ViewGroup.mise en page(ViewGroup.java: 4364) au Android.soutien.conception.widget.HeaderScrollingViewBehavior.layoutChild (HeaderScrollingViewBehavior.java: 132) à Android.soutien.conception.widget.ViewOffsetBehavior.onLayoutChild (ViewOffsetBehavior.java: 42) à Android.de soutien.conception.widget de.AppBarLayout$ScrollingViewBehavior.onLayoutChild (AppBarLayout.java: 1361) au Android.soutien.conception.widget.CoordinatorLayout.onLayout (CoordinatorLayout.java: 869) au android.vue.Vue.mise en page(à Vue.java: 13754) au android.vue.ViewGroup.mise en page(ViewGroup.java: 4364) au android.de soutien.v4.vue.ViewPager.onLayout (ViewPager.java: 1767) au android.vue.Vue.mise en page(à Vue.java: 13754) au android.vue.ViewGroup.mise en page(ViewGroup.java: 4364) au android.widget.LinearLayout.setChildFrame (LinearLayout.java: 1649) au android.widget.LinearLayout.layoutVertical(LinearLayout.java: 1507) au android.widget.LinearLayout.onLayout (LinearLayout.java: 1420) au android.vue.Vue.mise en page(à Vue.java: 13754) au android.vue.ViewGroup.mise en page(ViewGroup.java: 4364) au android.widget.FrameLayout.onLayout (FrameLayout.java: 448) au android.vue.Vue.mise en page(à Vue.java: 13754) au android.vue.ViewGroup.mise en page(ViewGroup.java: 4364) au android.widget.FrameLayout.onLayout (FrameLayout.java: 448) au android.vue.Vue.mise en page(à Vue.java: 13754) au android.vue.ViewGroup.mise en page(ViewGroup.java: 4364) au android.widget.LinearLayout.setChildFrame (LinearLayout.java: 1649) au android.widget.LinearLayout.layoutVertical(LinearLayout.java: 1507) au android.widget.LinearLayout.onLayout (LinearLayout.java: 1420) à Android.vue.Vue.mise en page(à Vue.java: 13754) au android.vue.ViewGroup.mise en page(ViewGroup.java: 4364) au android.widget.FrameLayout.onLayout (FrameLayout.java: 448) au android.vue.Vue.mise en page(à Vue.java: 13754) à Android.vue.ViewGroup.mise en page(ViewGroup.java: 4364) au android.widget.FrameLayout.onLayout (FrameLayout.java: 448) au android.vue.Vue.mise en page(à Vue.java: 13754) au android.vue.ViewGroup.mise en page Vi

5
répondu Francis Bacon 2017-11-15 12:22:24

avec la bibliothèque de soutien actuelle D'AppCompat, vous pouvez utiliser app:tint sur ImageView étiquette qui sera gonflée comme AppCompatImageView et gérer le changement d'état correctement.

dans AppCompatImageView , vous pouvez voir que mImageHelper est notifié du changement d'état:

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

Android Studio donne actuellement un avertissement à ce sujet, mais vous pouvez le supprimer en toute sécurité.

3
répondu Dreaming in Code 2017-06-19 15:17:58