web-dev-qa-db-fra.com

Comment utiliser le sélecteur pour teinter imageview dans android

Je veux teinter les icônes de mon tabhost en utilisant xml, au lieu de le faire par programme (je n'ai pas pu le faire de toute façon) ... J'ai donc trouvé ce fil sur SO: Android imageview change teinte pour simuler le clic du bouton

Cela semble être une assez 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 référencer @drawable/selector.xml à Android:tint, donc je l'ai fait sur 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>

Ma disposition des onglets:

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

Aucune suggestion? Merci d'avance

[EDIT] J'obtenais un NumberFormatException pour utiliser Android:tint, quand la bonne était app:tint (après avoir défini xmlns:app="http://schemas.Android.com/apk/res/com.myapp") ... mais maintenant je pense que j'utilise mal mon sélecteur, car les icônes sont toutes noires, peu importe l'état ... J'ai essayé de régler <drawable name="tab_icon_selector">@drawable/tab_icon_selector</drawable> à partir de colors.xml, n'a pas fonctionné

[/MODIFIER]

27
Lucas Jota

En référence à ma solution sur https://stackoverflow.com/a/18724834/2136792 , il manque quelques éléments:

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 dessinable à partir d'un dessinable puisse causer un problème, mais vous pouvez simplement déplacer votre selector.xml dans un dossier "/ res/color" pour le référencer avec "@ color/selector.xml" (aapt fusionne à la fois /res/values/colors.xml et le dossier/res/color).

11
Stephen Kidson

Si vous êtes dans l'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>
32
Christopher Perry

J'ai implémenté cela en utilisant DrawableCompat à partir de la bibliothèque Android support-v4).

Avec un ImageButton régulier (qui sous-classe ImageView, donc cette information s'applique également aux ImageViews), en utilisant une icône noire de la collection d'icônes de matériaux :

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

Voici 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 lorsque le bouton est enfoncé:

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

Une fois la ImageButton gonflée dans la méthode onCreate() de mon activité, je n'appelle la méthode d'assistance tintButton(...) qu'une seule fois pour chaque bouton.


J'ai testé cela sur Android 4.1 (mes minSdkVersion) et les appareils 5.0, mais DrawableCompat devrait fonctionner à Android 1.6.

19
Christopher Orr

Avec la bibliothèque de support 22.1, nous pouvons utiliser DrawableCompat pour teinter le dessin, API niveau 4+

DrawableCompat.wrap (Drawable) et setTint (), setTintList () et setTintMode () fonctionneront juste: pas besoin de créer et de maintenir des drawables séparés uniquement pour prendre en charge plusieurs couleurs!

10
bugraoral

Je suis d'accord avec @Dreaming dans Code et je vais vous 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>

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

Attention: Nous devons utiliser app: tint au lieu de Android: tint .

Ma version de bibliothèque de support est 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'

Si nous utilisons Android: tint, il plantera et le journal sera comme ceci:

E/AndroidRuntime: FATAL EXCEPTION: main Android.view.InflateException: ligne de fichier XML binaire # 0: erreur de gonflement de la classe sur Android.view.LayoutInflater.createView (LayoutInflater.Java:613) sur Android.view.LayoutInflater.createViewFromTag (LayoutInflater. Java: 687) sur Android.view.LayoutInflater.rInflate (LayoutInflater.Java:746) sur Android.view.LayoutInflater.inflate (LayoutInflater.Java:489) sur Android.view.LayoutInflater.inflate (LayoutInflater.Java:396) sur com.opera.six.viewholder.post.PostCountInfoViewHolder $ 1.create (PostCountInfoViewHolder.Java:29) sur com.opera.six.viewholder.post.PostCountInfoViewHolder $ 1.create (PostCountInfoViewHolder.Java:25) sur com.opera.six. collection.CollectionAdapter.onCreateViewHolder (CollectionAdapter.Java:39) sur com.opera.six.collection.CollectionAdapter.onCreateViewHolder (CollectionAdapter.Java:19) sur Android.support.v7.widget.RecyclerView $ Adapter.createViewHolder (RecyclerView.Java: 6493) sur Android.support.v7.widget.RecyclerView $ Recycler.tryGetViewHolderForPosit ionByDeadline (RecyclerView.Java:5680) sur Android.support.v7.widget.RecyclerView $ Recycler.getViewForPosition (RecyclerView.Java:5563) sur Android.support.v7.widget.RecyclerView $ Recycler.getViewForPosition (RecyclerView.Java:5559) sur Android.support.v7.widget.LinearLayoutManager $ LayoutState.next (LinearLayoutManager.Java:2229) sur Android.support.v7.widget.LinearLayoutManager.layoutChunk (LinearLayoutManager.Java:1556) sur Android.support.v7.widget.Lin .fill (LinearLayoutManager.Java:1516) sur Android.support.v7.widget.LinearLayoutManager.onLayoutChildren (LinearLayoutManager.Java:608) sur Android.support.v7.widget.RecyclerView.dispatchLayoutStep2 (RecyclerView.Java:93: Android). support.v7.widget.RecyclerView.dispatchLayout (RecyclerView.Java:3410) sur Android.support.v7.widget.RecyclerView.onLayout (RecyclerView.Java:3962) sur Android.view.View.layout (View.Java:13754) à Android.view.ViewGroup.layout (ViewGroup.Java:4364) à Android.support.v4.widget.SwipeRefreshLayout.onLayout (SwipeR efreshLayout.Java:610) sur Android.view.View.layout (View.Java:13754) sur Android.view.ViewGroup.layout (ViewGroup.Java:4364) sur Android.support.design.widget.HeaderScrollingViewBehavior.layoutChild (HeaderScrollingViewBe .Java: 132) sur Android.support.design.widget.ViewOffsetBehavior.onLayoutChild (ViewOffsetBehavior.Java:42) sur Android.support.design.widget.AppBarLayout $ ScrollingViewBehavior.onLayoutChild (AppBarLayout.Java.support). design.widget.CoordinatorLayout.onLayout (CoordinatorLayout.Java:869) sur Android.view.View.layout (View.Java:13754) sur Android.view.ViewGroup.layout (ViewGroup.Java:4364) sur Android.support.v4 .view.ViewPager.onLayout (ViewPager.Java:1767) sur Android.view.View.layout (View.Java:13754) sur Android.view.ViewGroup.layout (ViewGroup.Java:4364) sur Android.widget.LinearLayout. setChildFrame (LinearLayout.Java:1649) sur Android.widget.LinearLayout.layoutVertical (LinearLayout.Java:1507) sur Android.widget.LinearLayout.onLayout (LinearLayout.Java:1420) sur Android. view.View.layout (View.Java:13754) sur Android.view.ViewGroup.layout (ViewGroup.Java:4364) sur Android.widget.FrameLayout.onLayout (FrameLayout.Java:448) sur Android.view.View.layout (View.Java:13754) sur Android.view.ViewGroup.layout (ViewGroup.Java:4364) sur Android.widget.FrameLayout.onLayout (FrameLayout.Java:448) sur Android.view.View.layout (View.Java: 13754) sur Android.view.ViewGroup.layout (ViewGroup.Java:4364) sur Android.widget.LinearLayout.setChildFrame (LinearLayout.Java:1649) sur Android.widget.LinearLayout.layoutVertical (LinearLayout.Java:1507) sur Android. widget.LinearLayout.onLayout (LinearLayout.Java:1420) sur Android.view.View.layout (View.Java:13754) sur Android.view.ViewGroup.layout (ViewGroup.Java:4364) sur Android.widget.FrameLayout.onLayout (FrameLayout.Java:448) sur Android.view.View.layout (View.Java:13754) sur Android.view.ViewGroup.layout (ViewGroup.Java:4364) sur Android.widget.FrameLayout.onLayout (FrameLayout.Java: 448) sur Android.view.View.layout (View.Java:13754) sur Android.view.ViewGrou p.layout (Vi

7
Francis Bacon

Avec la bibliothèque de support AppCompat actuelle, vous pouvez utiliser app:tint on ImageView tag qui sera gonflé comme AppCompatImageView et gérera 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é.

4
Hai Zhang