Android RatingBar change les couleurs des étoiles [fermé]

141

Comment puis-je changer les couleurs et la taille des étoiles?

d-man
la source
Je pense que vous devez créer votre propre barre de notation personnalisée si vous voulez faire cela
Donal Rafferty
J'ai écrit un article de blog décrivant comment changer les images de RatingBar: kozyr.zydako.net/2010/05/23/pretty-ratingbar Il montre également où vous pouvez spécifier la taille de l'image ...
kozyr
J'espérais que cette question concerne la barre de notation multicolore comme indiqué sur les sites Web, je n'ai pas pu en trouver une pour moi. J'ai créé moi-même une implémentation simple github.com/codebreaker/coloredratingbar-android . J'espère que cela aide quelqu'un là-bas.
jaga

Réponses:

26

Étape 1: Créez votre propre style, en clonant l'un des styles existants (à partir de $ANDROID_HOME/platforms/$SDK/data/res/values/styles.xml), en le plaçant dans votre propre projet styles.xmlet en le référençant lorsque vous ajoutez le widget à une mise en page.

Étape 2: Créez vos propres LayerDrawableressources XML pour le RatingBar, en pointant vers les images appropriées à utiliser pour la barre. Les styles originaux vous indiqueront les ressources existantes avec lesquelles vous pouvez comparer. Ensuite, ajustez votre style pour utiliser vos propres LayerDrawableressources, plutôt que celles intégrées.

CommonsWare
la source
1
Comme à l'étape 2, cela ne fonctionne pas pour les appareils Samsung 3 ou certains autres, il n'est pas nécessaire que ce soit un LayerDrawable. Voir ici pour info: stackoverflow.com/questions/30266334/…
Kenny
6
Utilisez Android: progressTint = "@ color / yellow". Voir la réponse de @superpuccio.
Vincent
2
progressTint pris en charge uniquement au-dessus du niveau 21 de l'API
Yogesh Rathi
C'est la meilleure solution: stackoverflow.com/a/36297738/1935135
André Luiz Reis
120

C'est un peu compliqué sur le blog mentionné, j'ai utilisé un moyen similaire mais plus simple. Vous avez besoin d'images 3 étoiles (red_star_full.png, red_star_half.png et red_star_empty.png) et d'un xml, c'est tout.

Mettez ces 3 images à res / drawable.

Mettez là le ratingbar_red.xml suivant:

<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background" android:drawable="@drawable/red_star_empty" />
    <item android:id="@android:id/secondaryProgress" android:drawable="@drawable/red_star_half" />
    <item android:id="@android:id/progress" android:drawable="@drawable/red_star_full" />
</layer-list>

et, enfin, indiquez à votre définition de barre de notation d'utiliser ceci, c'est-à-dire

<RatingBar android:progressDrawable="@drawable/ratingbar_red"/>

C'est tout.

Alex
la source
3
Salut Alex, j'ai essayé cette solution, mais lorsque j'essaie de définir la note sur quelque chose comme 1,1, 1,2, etc., elle s'affiche comme 1,5. J'ai pris des images 3 étoiles, une vide, une à moitié pleine et une pleine. Je suppose qu'il est censé interpoler entre eux pour obtenir les composants fractionnaires, je me demande simplement si quelqu'un d'autre a eu le même problème ou est-ce que je fais quelque chose de très mal?
Graham Baitson
Pouvez-vous s'il vous plaît me téléphoner à propos des images que nous devrions utiliser, c'est une image colorée et la taille des images que je ne suis pas en mesure de résoudre ...
Prithviraj Shiroor
1
Tout le monde voit la réponse de la mise à jour 2015 ci-dessous! C'est beaucoup plus facile et plus simple!
katie
Cette réponse offre encore plus de flexibilité sur les différents états des étoiles.
Tom Brinkkemper
Pourquoi j'obtiens des lignes verticales sous les étoiles? J'ai essayé de définir un style personnalisé, en spécifiant la hauteur, mais il y a toujours des lignes verticales sous les étoiles sur mon AVD.
Aleksandar
93

Essayez ceci, si vous souhaitez uniquement changer de couleur:

RatingBar ratingBar = (RatingBar) findViewById(R.id.ratingBar);
LayerDrawable stars = (LayerDrawable) ratingBar.getProgressDrawable();
stars.getDrawable(2).setColorFilter(Color.YELLOW, PorterDuff.Mode.SRC_ATOP);
Mirek Michalak
la source
1
Que veut PorterDuff.Mode.SRC_ATOPdire ou faire exactement ?
Zapnologica
5
Ne fonctionne pas sur l'API 5.0 et plus. Besoins:Drawable stars = rb.getProgressDrawable(); stars.setTint( Color.YELLOW );
zyamys
@zyamys C'est vraiment nul = (Une méthode pour les "versions supérieures" et une autre méthode pour les anciennes versions est-elle nécessaire?
Daniela Morais
1
Cela ne fonctionne que pour une précision de 0,5. Sinon (précision <0,5), la superposition devient bizarre et semble que la couleur bleue est toujours avec une précision de 0,5 tandis que le jaune est précis
Teo Inke
1
Avertissement: plante sur les appareils pré-lolipop. Allez avec la réponse acceptée.
blockwala du
70

La manière la plus simple qui a fonctionné pour moi ... si vous étendez l'activité AppCompat

Dans votre build.gradle, ajoutez la dernière bibliothèque appcompat.

dependencies {  
    compile 'com.android.support:appcompat-v7:X.X.X' // where X.X.X version
}

Faites étendre votre activité android.support.v7.app.AppCompatActivity

public class MainActivity extends AppCompatActivity {  
    ...
}

Déclarez un style personnalisé dans votre fichier styles.xml.

<style name="RatingBar" parent="Theme.AppCompat">  
    <item name="colorControlNormal">@color/indigo</item>
    <item name="colorControlActivated">@color/pink</item>
</style>  

Appliquez ce style à votre RatingBar via l'attribut android: theme.

<RatingBar  
    android:theme="@style/RatingBar"
    android:rating="3"
    android:stepSize="0.5"
    android:numStars="5"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
Vishal Kumar
la source
3
Merci @Vishal Kumar. Je l'ai essayé sur Kitkat 4.4.4 (Samsung S3 neo) et Marshmallow 6.0.1 (Samsung Galaxy On Nxt), cela a fonctionné. Mais pas de succès sur Lollipop 5.1 (Micromax). Pour Lollipop, j'ai utilisé l'attribut "android: progressTint" dans RatingBar et oui cela fonctionne.
Prashant
C'est la meilleure solution.
Arhat Baid
Cela devrait être la bonne réponse sélectionnée.
Hampel Előd
1
C'est la meilleure solution. Si vous souhaitez modifier la taille de l'étoile, vous pouvez utiliser style="?android:ratingBarStyleSmall"ensemble.
André Luiz Reis
@ AndréLuizReis <style name="RatingBarSmallTheme" parent="Theme.AppCompat"> <item name="colorControlNormal">@color/colorOrangeNormal</item> <item name="colorControlActivated">@color/colorOrangeActivated</item> <item name="ratingBarStyle">@style/Widget.AppCompat.RatingBar.Small</item> </style> et votre ratingBar android:theme="@style/RatingBarSmallTheme"
Zakhar Rodionov
47

Mise à jour 2015

Vous pouvez maintenant utiliser DrawableCompat pour teinter tous les types de dessinables. Par exemple:

Drawable progress = ratingBar.getProgressDrawable();
DrawableCompat.setTint(progress, Color.WHITE);

Ceci est rétrocompatible jusqu'à l'API 4

lgvalle
la source
N'oubliez pas de remettre le drawable sur le ratingBar.
Squeeish
15
Cela teinte l'ensemble du dessinable en une seule couleur, ce qui rend les étoiles vides très difficiles à distinguer.
blueice
Cela fonctionne uniquement avec la bibliothèque de support Android> = 22 et non avec la bibliothèque de support <22.
Raghav Sharma
2
Il dessine 5 étoiles colorées, pas 3,5.
CoolMind
1
Je voudrais juste entourer cela if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {}car il fonctionne par défaut à partir de l'API 22.
Yoann Hercouet
38

Depuis l'API 21 , il est très facile de changer la couleur des étoiles avec ces trois lignes de code:

android:progressTint="@android:color/holo_red_dark"
android:progressBackgroundTint="@android:color/holo_red_dark"
android:secondaryProgressTint="@android:color/holo_red_dark" 

En faisant comme ça, vous allez changer:

  • la couleur des étoiles remplies (progressTint)
  • la couleur des étoiles non remplies (progressBackgroundTint)
  • et la couleur de la bordure (secondaryProgressTint) des étoiles
superpuccio
la source
Au lieu de 3,5, il peint 4 étoiles.
CoolMind
@CoolMind set android: stepSize: 1 au lieu de 0.5
eLemEnt
4
Comment changer la couleur d'une étoile vide?
winklerrr
@winklerrr avez-vous trouvé une solution pour changer la couleur d'une étoile vide.
Tarun Kumar
N'a pas fait d'autres vérifications pour trouver une solution
winklerrr
36

Si vous voulez changer la couleur de toutes les étoiles, vous dites mon utilisation:

LayerDrawable stars = (LayerDrawable) ratingBar.getProgressDrawable();
stars.getDrawable(2).setColorFilter(getResources().getColor(R.color.starFullySelected), PorterDuff.Mode.SRC_ATOP);
stars.getDrawable(1).setColorFilter(getResources().getColor(R.color.starPartiallySelected), PorterDuff.Mode.SRC_ATOP);
stars.getDrawable(0).setColorFilter(getResources().getColor(R.color.starNotSelected), PorterDuff.Mode.SRC_ATOP);
Yuriy Vinogradov
la source
Existe-t-il des moyens de définir la couleur des étoiles en fonction des données extraites de la base de données? Disons que j'ai obtenu 5 étoiles et que les données renvoyées par la base de données étaient de 4. Donc, au lieu de changer les 5 étoiles, je ne change que les 4 premières
1
getColor est obsolète maintenant, une alternative?
Manohar Reddy le
2
Vous pouvez trouver des réponses ici stackoverflow.com/a/32202256/2513291 Par exemple cette approche ContextCompat.getColor (context, R.color.color_name)
Yuriy Vinogradov
fonctionne bien, mais notez que, pour une raison quelconque, l'ordre est important (2, puis 1, puis 0). J'ai essayé l'inverse et cela a conduit à des problèmes d'interface utilisateur la première fois que la couleur est modifiée.
Simon Ninon
25

Les solutions publiées par Alex et CommonsWares sont correctes. Une chose dont Android ne parle jamais est la taille des pixels appropriée pour différentes densités. Voici les dimensions requises pour chaque densité en fonction de la lumière halo.

Petite étoile

mdpi: 16px
hdpi: 24px
xhdpi: 32px
xxhdpi: 48px

Étoile moyenne

mdpi: 24px
hdpi: 36px
xhdpi: 48px
xxhdpi: 72px

Grande étoile

mdpi: 35px
hdpi: 52px
xhdpi: 69px
xxhdpi: 105px
Dirkoneill
la source
puis-je utiliser vectordrawble avec des étoiles
Mina Fawzy
24

Cela fait donc deux heures que je lutte avec ce problème et j'ai mis au point une solution fonctionnelle pour toutes les versions d'API, où les notes demi-étoiles sont également affichées.

private void setRatingStarColor(Drawable drawable, @ColorInt int color)
{
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
    {
        DrawableCompat.setTint(drawable, color);
    }
    else
    {
        drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
    }
}

Vous appelez la méthode avec cet ordre de drawables:

    LayerDrawable stars = (LayerDrawable) ratingBar.getProgressDrawable();
    // Filled stars
    setRatingStarColor(stars.getDrawable(2), ContextCompat.getColor(getContext(), R.color.foreground));
    // Half filled stars
    setRatingStarColor(stars.getDrawable(1), ContextCompat.getColor(getContext(), R.color.background));
    // Empty stars
    setRatingStarColor(stars.getDrawable(0), ContextCompat.getColor(getContext(), R.color.background));

REMARQUE: vous devez également spécifier les attributs "max" et "numStars" en XML, sinon les demi-étoiles ne sont pas affichées.

boîte
la source
le seul moyen qui fonctionne pour moi sur API19, mais je n'ai pas abandonné pour chercher un moyen de le faire à partir de xml uniquement
T_T
@BeeingJk si vous créez une vue personnalisée qui étend RatingBar, vous pouvez créer vos propres attributs xml pour spécifier la couleur de la teinte. Vous disposez alors d'un point de contrôle unique pour définir la teinte et pouvez spécifier la teinte en xml. J'espère que cela pourra aider! Peut expliquer plus si nécessaire
Forrest Bice
Mode.SRC_INou Mode.MULTIPLY?
Dr.jacky
12

Vous pouvez maintenant utiliser DrawableCompat à partir d'AppCompat v22.1.0 pour colorer dynamiquement tous les types de dessinables, utile lorsque vous prenez en charge plusieurs thèmes avec un seul ensemble de dessinables. Par exemple:

LayerDrawable layerDrawable = (LayerDrawable) ratingBar.getProgressDrawable();
DrawableCompat.setTint(DrawableCompat.wrap(layerDrawable.getDrawable(0)), Color.RED);   // Empty star
DrawableCompat.setTint(DrawableCompat.wrap(layerDrawable.getDrawable(1)), Color.GREEN); // Partial star
DrawableCompat.setTint(DrawableCompat.wrap(layerDrawable.getDrawable(2)), Color.BLUE);  // Full star

Ceci est rétrocompatible jusqu'à l'API 4. Voir également l'article de blog de Chris Banes sur les bibliothèques de support v22.1.0

Pour la taille et la forme réelles, vous devrez définir un nouveau style et une nouvelle liste de calques pour la taille appropriée, car d'autres ont déjà répondu ci-dessus.

Dan Dar3
la source
Les drawables ne sont pas des tableaux. Comment accédez-vous à progress [0]?
blueice
@blueice Vous avez raison désolé, Drawable devrait être un LayerDrawable, corrigé maintenant, merci.
Dan Dar3
Cela ne semblait toujours pas fonctionner pour moi, j'ai fini avec ce que Yuriy Vinogradov a mis dans une réponse différente à cette question et cela semble fonctionner.
blueice
Comment changer Drawable à la place Changer de couleur?
Iman Marashi
@ImanMarashi Voir la réponse XML d'Alex ci-dessus, LayerDrawable.setDrawable (index, drawable) n'est disponible qu'à partir d'API23.
Dan Dar3
10

Utilisation android:theme attribut:

styles.xml

<style name="Theme.Rating" parent="Theme.AppCompat.Light">
    <item name="colorAccent">@color/rating</item>
</style>

layout.xml

<android.support.v7.widget.AppCompatRatingBar
    android:theme="@style/Theme.Rating"
    android:numStars="5"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
hidro
la source
9

Pour changer simplement la couleur de la barre de notation à partir de xml: -

android:progressTint="@color/your_color"
android:backgroundTint="@color/your_color"
android:secondaryProgressTint="@color/your_color"
Rahul
la source
ça ne change pas la couleur de l'étoile vide
Nainal
7

Pour changer la couleur il vous suffit de mettre set le paramètre android: progressTint

 <RatingBar
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_marginTop="15dp"
        android:numStars="5"
        android:rating="1"
        android:progressTint="@android:/color/black"
        android:layout_gravity="center"
       />

Pour la taille, la propriété de style.

letrounet
la source
fonctionne uniquement sur API 21 ou supérieur, merci
Junaid
5

Le moyen le plus simple:

android:progressTint="@color/color"
Mehatab
la source
1
Notez que cela ne fonctionne que sur api 21+
Ixx
4

Réponse de Building @ lgvalle.

Mise à jour 2015

Vous pouvez maintenant utiliser DrawableCompat pour teinter tous les types de dessinables. Par exemple:

Drawable progress = ratingBar.getProgressDrawable (); DrawableCompat.setTint (progression, Color.WHITE); Ceci est rétrocompatible jusqu'à l'API 4

LayerDrawable drawable = (LayerDrawable) getProgressDrawable();
Drawable progress = drawable.getDrawable(2);
DrawableCompat.setTint(progress, getResources().getColor(COLOR1));
progress = drawable.getDrawable(1);
DrawableCompat.setTintMode(progress, PorterDuff.Mode.DST_ATOP);
DrawableCompat.setTint(progress, getResources().getColor(COLOR1));
DrawableCompat.setTintMode(progress, PorterDuff.Mode.SRC_ATOP);
DrawableCompat.setTint(progress, getResources().getColor(COLOR2));
progress = drawable.getDrawable(0);
DrawableCompat.setTint(progress, getResources().getColor(COLOR2));

Cela conservera les couleurs des pas de fraction.

Splangi
la source
4
<!--For rating bar -->
    <style name="RatingBarfeed" parent="Theme.AppCompat">
        <item name="colorControlNormal">@color/colorPrimary</item>
        <item name="colorControlActivated">@color/colorPrimary</item>
    </style>

utilisez votre propre couleur

Sibasish
la source
4

Sans ajouter un nouveau style, vous pouvez utiliser la couleur de teinte dans le RatingBar

             <RatingBar
                    android:id="@+id/ratingBar"
                    style="@android:style/Widget.Holo.RatingBar.Small"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:numStars="5"
                    android:rating="4.5"
                    android:stepSize="0.5"
                    android:progressTint="@color/colorPrimary"/>
4ndro1d
la source
3

Fonctionne pour Android au-dessous et au-dessus de la version 21

Après quelques recherches, j'ai mis au point cette méthode pour définir la teinte d'arrière-plan, la teinte de l'écart (ex: demi-étoile) et la couleur de la teinte étoile.

LayerDrawable layers = (LayerDrawable) ratingBar.getProgressDrawable();
DrawableCompat.setTint(layers.getDrawable(0), 0x33000000); // The background tint
DrawableCompat.setTint(layers.getDrawable(1), 0x00000000); // The gap tint (Transparent in this case so the gap doesnt seem darker than the background)
DrawableCompat.setTint(layers.getDrawable(2), 0xffFED80A); // The star tint
Arbitur
la source
3

Solution simple, utilisez AppCompatRatingBar et sa méthode setProgressTintList pour y parvenir, consultez cette réponse pour référence.

Kuldeep Sakhiya
la source
Cela a fonctionné pour moi sous API 28 en utilisant com.google.android.material: matériel: 1.1.0-alpha02
Mark
2

Je résous ce problème comme suit:

LayerDrawable layerDrawable = (LayerDrawable) ratingBar.getProgressDrawable();

DrawableCompat.setTint(DrawableCompat.wrap(layerDrawable.getDrawable(0)),
                       Color.WHITE);  // Empty star
DrawableCompat.setTint(DrawableCompat.wrap(layerDrawable.getDrawable(1)),
                       Color.YELLOW); // Partial star
DrawableCompat.setTint(DrawableCompat.wrap(layerDrawable.getDrawable(2)),
                       Color.YELLOW);
Hai Rom
la source
Merci, ça marche. Mais pour les notes fractionnaires, les étoiles sont entièrement peintes.
CoolMind
2
RatingBar mRating=(RatingBar)findViewById(R.id.rating);
 LayerDrawable layerDrawable=(LayerDrawable)mRating.getProgressDrawable();
 layerDrawable.getDrawable(2).setColorFilter(Color.parseColor
 ("#32CD32"),    PorterDuff.Mode.SRC_ATOP);

pour moi, ça marche ...

Vimesh Pk
la source
1

J'ai trouvé une solution simple pour changer la couleur de l'étoile en fonction de votre thème.

Aller à ce site: http://android-holo-colors.com/

Choisissez la couleur de votre thème et créez vos images étoiles.

Hardik4560
la source
1

En utilisant les réponses ci-dessus, j'ai créé une méthode statique rapide qui peut facilement être réutilisée. Il vise uniquement à teinter la couleur de progression des étoiles activées. Les étoiles qui ne sont pas activées restent grises.

    public static RatingBar tintRatingBar (RatingBar ratingBar, int progressColor)if (ratingBar.getProgressDrawable() instanceof LayerDrawable) {
        LayerDrawable progressDrawable = (LayerDrawable) ratingBar.getProgressDrawable();
        Drawable drawable = progressDrawable.getDrawable(2);
        Drawable compat = DrawableCompat.wrap(drawable);
        DrawableCompat.setTint(compat, progressColor);
        Drawable[] drawables = new Drawable[3];
        drawables[2] = compat;

        drawables[0] = progressDrawable.getDrawable(0);
        drawables[1] = progressDrawable.getDrawable(1);

        LayerDrawable layerDrawable = new LayerDrawable(drawables);

        ratingBar.setProgressDrawable(layerDrawable);

        return ratingBar;
    }
    else {
        Drawable progressDrawable =  ratingBar.getProgressDrawable();
        Drawable compat = DrawableCompat.wrap(progressDrawable);
        DrawableCompat.setTint(compat, progressColor);
        ratingBar.setProgressDrawable(compat);
        return ratingBar;
    }
}

Passez simplement votre barre de notation et une couleur en utilisant getResources().getColor(R.color.my_rating_color)

Comme vous pouvez le voir, j'utilise DrawableCompat donc il est rétrocompatible.

EDIT: Cette méthode ne fonctionne pas sur API21 (allez comprendre pourquoi). Vous vous retrouvez avec une NullPointerException lors de l'appel de setProgressBar. J'ai fini par désactiver toute la méthode sur API> = 21.

Pour API> = 21, j'utilise la solution SupperPuccio.

JDenais
la source
java.lang.ClassCastException: android.support.v4.graphics.drawable.DrawableWrapperHoneycomb ne peut pas être converti en android.graphics.drawable.LayerDrawable sur pré-lollipop
Ishaan Garg
1
@IshaanGarg vous avez raison. J'ai rencontré le même problème et mis à jour ma méthode. J'ai mis à jour mon code pour gérer le cas. Je ne pense pas que ce soit une question de version Android. Si vous utilisez la version plus petite de la barre d'évaluation (avec style = "? Android: attr / ratingBarStyleSmall"), alors le dessinable renvoyé est toujours un LayoutDrawable.
JDenais
Ouais, juste ce que j'avais mis en œuvre, assurez-vous simplement d'utiliser AppCompatRatingBar. Bien que je ne puisse pas obtenir une demi-étoile lors de la pré-configuration de la note de XML / java. Comme ensembleL'évaluation (3,5) montre 4 étoiles complètes
Ishaan Garg
1

La barre de notation est utilisée automatiquement au moment de l'exécution pour changer la couleur de l'étoile tactile.

Ajoutez d'abord le style dans le fichier app \ src \ main \ res \ values ​​\ styles.xml:

<style name="RatingBar" parent="Theme.AppCompat">
    <item name="colorControlNormal">@android:color/darker_gray</item>
    <item name="colorControlActivated">@color/com_facebook_blue</item>
</style>

Ensuite, votre barre d'évaluation ajoute un thème comme celui-ci:

<RatingBar
   android:id="@+id/rating"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:numStars="5"
   android:stepSize="1"
   android:theme="@style/RatingBar"/>
Navadip Patel
la source
0

1) déclarer ce xml

<LinearLayout 
             android:layout_width="match_parent"
        android:layout_height="wrap_content"
         android:layout_alignParentBottom="true"
         android:orientation="horizontal"
         android:paddingLeft="20dp"
         android:paddingRight="20dp"
         android:layout_marginBottom="20dp"
         android:background="#323232"
         android:gravity="center_horizontal">

       <com.example.android.custom_ratingbar.CustomRatingBar
        android:id="@+id/coloredRatingBar5"
        style="@style/coloredRatingBarStyleSmall"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"

         />
       </LinearLayout>

2) dans style.xml

<style name="coloredRatingBarStyleSmall">
        <item name="indicator">false</item>
        <item name="type">small</item>
    </style>

3)

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class CustomRatingBar extends View{

    private static final String TAG="ColoredRatingBar";
    private static final int NORMAL = 0;
    private static final int SMALL = 1;

    Bitmap[] drawables;
    Bitmap progressBackground;
    Context mContext;
    private int mNumStars =9;
    private float mRating =0;
    private boolean mIndicator;
    private float slidePosition;
    private int mType;

    /**
     * A callback that notifies clients when the rating has been changed. This
     * includes changes that were initiated by the user through a touch gesture
     * or arrow key/trackball as well as changes that were initiated
     * programmatically.
     */
    public interface OnRatingBarChangeListener {

        /**
         * Notification that the rating has changed. Clients can use the
         * fromUser parameter to distinguish user-initiated changes from those
         * that occurred programmatically. This will not be called continuously
         * while the user is dragging, only when the user finalizes a rating by
         * lifting the touch.
         *
         * @param ratingBar The RatingBar whose rating has changed.
         * @param rating The current rating. This will be in the range
         *            0..numStars.
         * @param fromUser True if the rating change was initiated by a user's
         *            touch gesture or arrow key/horizontal trackbell movement.
         */
        void onRatingChanged(CustomRatingBar ratingBar, float rating, boolean fromUser);

    }

    private OnRatingBarChangeListener mOnRatingBarChangeListener;

    public CustomRatingBar(Context context) {
        this(context, null);
    }
    public CustomRatingBar(Context context, AttributeSet attrs) {
        this(context, attrs,0);//R.attr.coloredRatingBarStyle
    }

    public CustomRatingBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomRatingBar,defStyle, 0);
        final boolean indicator = a.getBoolean(R.styleable.CustomRatingBar_indicator, false);
        final float rating = a.getFloat(R.styleable.CustomRatingBar_setrating, -1);
        final int type = a.getInt(R.styleable.CustomRatingBar_type, 0);
        a.recycle();

        setIndicator(indicator);
        setRating(rating);
        setType(type);
        init(context);
    }

    public int getType() {
        return mType;
    }

    public void setType(int type) {
        this.mType = type;
    }

    private void init(Context context) {
        mContext = context;
        Resources res = getResources();
        if(mType==SMALL){
            drawables = new Bitmap[]{BitmapFactory.decodeResource(res, R.drawable.rating_inactive),BitmapFactory.decodeResource(res, R.drawable.rating_active)};
            progressBackground = BitmapFactory.decodeResource(res, R.drawable.rating_inactive);
        }else{
            drawables = new Bitmap[]{BitmapFactory.decodeResource(res, R.drawable.rating_inactive),BitmapFactory.decodeResource(res, R.drawable.rating_active)};
            progressBackground = BitmapFactory.decodeResource(res, R.drawable.rating_inactive);
        }

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //draw empty stars bg
        for(int i=0;i< mNumStars;i++){
            drawStar(canvas,i);
        }

    }


    private void drawStar(Canvas canvas, int position) {
        float fraction = mRating -(position);
        Bitmap ratedStar1 = getRatedStar();
        Paint paint=getPaint(position);
        int division=getSize();
        Bitmap ratedStar=null;
        Bitmap emptyStar=null;
       if(!isInEditMode()){
        ratedStar=Bitmap.createScaledBitmap(ratedStar1, division, division, false);
        emptyStar=Bitmap.createScaledBitmap(progressBackground, division, division, false);
       }
        if((position)< mRating){
            if(!isInEditMode()){
           canvas.drawBitmap(ratedStar,(position* division),0,paint);
            }

        } else{

                if(!isInEditMode()){
              canvas.drawBitmap(emptyStar,(position*division),0,null);

            }
        }


    }
    private int getSize(){
        return (getWidth()/mNumStars);
    }

    private Bitmap getRatedStar() {

        if(mRating==0){
            return drawables[0];
        }
        else{
            return drawables[1];
        }
    }

    private Paint getPaint(int position){
        int value=(255*(position+1))/mNumStars;
        String hexString=Integer.toHexString(value).equals("0")?"00":Integer.toHexString(value);
        String hexvalue="#"+hexString+"000000";//FEE98E
        //Log.e("TAG", position+"/"+value+"/"+hexvalue);

        Paint paint=new Paint();

        paint.setColor(Color.parseColor(hexvalue));

        return paint;
    }

    public int getNumStars() {
        return mNumStars;
    }

    public void setNumStars(int numStars) {
        this.mNumStars = numStars;
    }

    public float getRating() {
        return mRating;
    }

    public void setRating(float rating) {
        setRating(rating,false);
    }

    void setRating(float rating,boolean fromUser) {
        if(rating>mNumStars){
            this.mRating = mNumStars;
        }
        this.mRating = rating;
        invalidate();
        dispatchRatingChange(fromUser);
    }

    public boolean isIndicator() {
        return mIndicator;
    }

    public void setIndicator(boolean indicator) {
        this.mIndicator = indicator;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (progressBackground != null) {

            final int width = progressBackground.getWidth() * mNumStars;
            final int height = progressBackground.getHeight();

            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
            Bitmap emptyStar=Bitmap.createScaledBitmap(progressBackground, widthSize/mNumStars, widthSize/mNumStars, false);
            int heightSize = emptyStar.getHeight();

            setMeasuredDimension(resolveSizeAndState(widthSize, widthMeasureSpec, 0),
                    resolveSizeAndState(heightSize, heightMeasureSpec, 0));
        }
        else{
              int desiredWidth = 100;
            int desiredHeight = 50;

            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
            int heightSize = MeasureSpec.getSize(heightMeasureSpec);

            int width;
            int height;

            //Measure Width
            if (widthMode == MeasureSpec.EXACTLY) {
                //Must be this size
                width = widthSize;
            } else if (widthMode == MeasureSpec.AT_MOST) {
                //Can't be bigger than...
                width = Math.min(desiredWidth, widthSize);
            } else {
                //Be whatever you want
                width = desiredWidth;
            }

            //Measure Height
            if (heightMode == MeasureSpec.EXACTLY) {
                //Must be this size
                height = heightSize;
            } else if (heightMode == MeasureSpec.AT_MOST) {
                //Can't be bigger than...
                height = Math.min(desiredHeight, heightSize);
            } else {
                //Be whatever you want
                height = desiredHeight;
            }

            //MUST CALL THIS
          setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, 0),resolveSizeAndState(height, heightMeasureSpec, 0));
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(mIndicator){
            return false;
        }

        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_UP:
                slidePosition = getRelativePosition(event.getX());

                int newRating = (int)(slidePosition>0?slidePosition+1:0) ;
                if(newRating>mNumStars){
                    newRating=mNumStars;
                }

             //   Log.e("TAG", ""+newRating);
                if (newRating != mRating) {
                    setRating(newRating,true);
                }
                break;
            case MotionEvent.ACTION_CANCEL:
                break;
            default:
                break;
        }

        return true;
    }

    private float getRelativePosition(float x) {
        Bitmap emptyStar=Bitmap.createScaledBitmap(progressBackground, getWidth()/mNumStars, getWidth()/mNumStars, false);
        int widthSize = emptyStar.getWidth();
      //  Log.e("TAG", widthSize+"/"+x);
         float position = x / widthSize;
       position = Math.max(position, 0);
       return Math.min(position, mNumStars);
    }

    /**
     * Sets the listener to be called when the rating changes.
     *
     * @param listener The listener.
     */
    public void setOnRatingBarChangeListener(OnRatingBarChangeListener listener) {
        mOnRatingBarChangeListener = listener;
    }

    /**
     * @return The listener (may be null) that is listening for rating change
     *         events.
     */
    public OnRatingBarChangeListener getOnRatingBarChangeListener() {
        return mOnRatingBarChangeListener;
    }

    void dispatchRatingChange(boolean fromUser) {
        if (mOnRatingBarChangeListener != null) {
            mOnRatingBarChangeListener.onRatingChanged(this, getRating(),
                    fromUser);
        }
    }
}


5) then in calling activity---

CustomRatingBar coloredRatingBar5=(CustomRatingBar)findViewById(R.id.coloredRatingBar5);
        coloredRatingBar5.setOnRatingBarChangeListener(new OnRatingBarChangeListener() {

            @Override
            public void onRatingChanged(CustomRatingBar ratingBar, float rating,boolean fromUser) {
                // TODO Auto-generated method stub
                Log.e("RATING", ""+rating);

            }
        });

6) évaluation active --- prenez n'importe quelle image avec une couleur sombre car elle sera utilisée comme transparence de couleur pour une évaluation différente

rating_inactive - prend n'importe quelle image de la même taille que l'image ci-dessus avec un arrière-plan clair .. elle sera utilisée lorsqu'aucune évaluation n'est sélectionnée

amit
la source
0

Un moyen très simple de changer la couleur de la bordure des étoiles consiste à utiliser le paramètre xml:

android:progressBackgroundTint=""

dans la vue ratingBar. La valeur doit être un code hexadécimal pour une couleur.

Pau Arlandis Martinez
la source
Je ne sais pas pourquoi, mais il semble que votre méthode n'affecte que la bordure des étoiles (la couleur de remplissage reste la couleur par défaut)
superpuccio
Ok, vous avez manqué des paramètres xml. Découvrez ma réponse ci-dessous.
superpuccio
1
Vous avez raison. Je ne sais pas pourquoi je pensais qu'il avait des problèmes pour changer la couleur de la bordure de l'étoile (peut-être parce que si le problème que j'avais). Votre réponse est plus complète.
Pau Arlandis Martinez
0

Je cherchais une méthode fiable pour faire tout cela jusqu'à l'API 9 au moins. La solution "casting vers LayerDrawble" me semblait être une solution risquée, et quand je l'ai testée sur un téléphone Android sur 2.3, elle a réussi mais l'appel à DrawableCompat.setTint (...) n'a eu aucun effet.

La nécessité de charger des ressources dessinables ne me semblait pas non plus une bonne solution.

J'ai décidé de coder ma propre solution qui est une classe étendant AppCompatRatingBar, en utilisant un Drawable personnalisé prenant soin de dessiner les étoiles par programme. Cela fonctionne parfaitement pour mes besoins, je le posterai au cas où cela aiderait quelqu'un:

https://gist.github.com/androidseb/2b8044c90a07c7a52b4bbff3453c8460

Le lien est plus simple car vous pouvez obtenir le fichier complet directement, mais voici le code complet au cas où:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.AppCompatRatingBar;
import android.util.AttributeSet;

/**
 * @author androidseb
 *         <p/>
 *         Extends AppCompatRatingBar with the ability to tint the drawn stars when selected, pressed and un-selected.
 *         Limitation: Only draws full stars.
 */
public class TintableRatingBar extends AppCompatRatingBar {
    private TintableRatingBarProgressDrawable progressDrawable;

    public TintableRatingBar(final Context context) {
        super(context);
        init();
    }

    public TintableRatingBar(final Context context, final AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public TintableRatingBar(final Context context, final AttributeSet attrs, final int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        progressDrawable = new TintableRatingBarProgressDrawable();
        setProgressDrawable(progressDrawable);
    }

    public void setCustomTintColors(final int _uncheckedColor, final int _pressedColor, final int _checkedColor) {
        progressDrawable.setRatingMaxLevelValue(getMax() * 1000);
        progressDrawable.setUnCheckedColor(_uncheckedColor);
        progressDrawable.setPressedColor(_pressedColor);
        progressDrawable.setCheckedColor(_checkedColor);
        invalidate();
    }

    public class TintableRatingBarProgressDrawable extends Drawable {
        private static final int STAR_COUNT = 5;
        private static final int STAR_BRANCHES_COUNT = 5;

        /** Sets the max level value: if the level is at the max, then all stars are selected. */
        private int ratingMaxLevelValue = 10000;
        /** Color to be painted for unselected stars */
        private int uncheckedColor = Color.GRAY;
        /** Color to be painted for unselected stars when the ratingbar is pressed */
        private int pressedColor = Color.CYAN;
        /** Color to be painted for selected stars */
        private int checkedColor = Color.BLUE;

        @Override
        public void setAlpha(final int _i) {
        }

        @Override
        public void setColorFilter(final ColorFilter _colorFilter) {
        }

        @Override
        public boolean isStateful() {
            return true;
        }

        @Override
        public boolean setState(final int[] stateSet) {
            final boolean res = super.setState(stateSet);
            invalidateSelf();
            return res;
        }

        @Override
        public int getOpacity() {
            return 255;
        }

        public void setRatingMaxLevelValue(final int _ratingMaxLevelValue) {
            ratingMaxLevelValue = _ratingMaxLevelValue;
        }

        public void setUnCheckedColor(final int _uncheckedColor) {
            uncheckedColor = _uncheckedColor;
        }

        public void setPressedColor(final int _pressedColor) {
            pressedColor = _pressedColor;
        }

        public void setCheckedColor(final int _checkedColor) {
            checkedColor = _checkedColor;
        }

        @Override
        public void draw(final Canvas _canvas) {
            boolean pressed = false;
            for (int i : getState()) {
                if (i == android.R.attr.state_pressed) {
                    pressed = true;
                }
            }

            final int level = (int) Math.ceil(getLevel() / (double) ratingMaxLevelValue * STAR_COUNT);
            final int starRadius = Math.min(getBounds().bottom / 2, getBounds().right / STAR_COUNT / 2);

            for (int i = 0; i < STAR_COUNT; i++) {
                final int usedColor;
                if (level >= i + 1) {
                    usedColor = checkedColor;
                } else if (pressed) {
                    usedColor = pressedColor;
                } else {
                    usedColor = uncheckedColor;
                }
                drawStar(_canvas, usedColor, (i * 2 + 1) * starRadius, getBounds().bottom / 2, starRadius,
                    STAR_BRANCHES_COUNT);
            }
        }

        private void drawStar(final Canvas _canvas, final int _color, final float _centerX, final float _centerY,
            final float _radius, final int _branchesCount) {
            final double rotationAngle = Math.PI * 2 / _branchesCount;
            final double rotationAngleComplement = Math.PI / 2 - rotationAngle;
            //Calculating how much space is left between the bottom of the star and the bottom of the circle
            //In order to be able to center the star visually relatively to the square when drawn
            final float bottomOffset = (float) (_radius - _radius * Math.sin(rotationAngle / 2) / Math.tan(
                rotationAngle / 2));
            final float actualCenterY = _centerY + (bottomOffset / 2);
            final Paint paint = new Paint();
            paint.setColor(_color);
            paint.setStyle(Style.FILL);
            final Path path = new Path();
            final float relativeY = (float) (_radius - _radius * (1 - Math.sin(rotationAngleComplement)));
            final float relativeX = (float) (Math.tan(rotationAngle / 2) * relativeY);
            final PointF a = new PointF(-relativeX, -relativeY);
            final PointF b = new PointF(0, -_radius);
            final PointF c = new PointF(relativeX, -relativeY);
            path.moveTo(_centerX + a.x, actualCenterY + a.y);
            _canvas.save();
            for (int i = 0; i < _branchesCount; i++) {
                path.lineTo(_centerX + b.x, actualCenterY + b.y);
                path.lineTo(_centerX + c.x, actualCenterY + c.y);
                rotationToCenter(b, rotationAngle);
                rotationToCenter(c, rotationAngle);
            }
            _canvas.drawPath(path, paint);
            _canvas.restore();
        }

        private void rotationToCenter(final PointF _point, final double _angleRadian) {
            final float x = (float) (_point.x * Math.cos(_angleRadian) - _point.y * Math.sin(_angleRadian));
            final float y = (float) (_point.x * Math.sin(_angleRadian) + _point.y * Math.cos(_angleRadian));
            _point.x = x;
            _point.y = y;
        }
    }
}
androidseb
la source
0

Réponse un peu tardive, mais j'espère que cela aidera certaines personnes.

<RatingBar
         android:id="@+id/rating"
         style="@style/Base.Widget.AppCompat.RatingBar.Small"
         android:theme="@style/WhiteRatingStar"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_below="@+id/profil_name"
         android:layout_centerHorizontal="true"
         android:layout_marginLeft="@dimen/dimen_4"
         android:rating="3" />

Et voici à quoi ressemble le WhiteRatingStar

<style name="WhiteRatingStar" parent="Base.Widget.AppCompat.RatingBar.Small">
     <item name="colorAccent">@android:color/white</item>
</style>

Avec cela, les étoiles seront colorées en blanc par exemple.

Martial Konvi
la source
-1

Comme l'indique la réponse précédente, il n'est pas facile de changer la couleur de la barre de notation. Les étoiles ne sont pas dessinées par programmation, ce sont des images de taille fixe et de dégradés de couleurs spécifiques. Pour changer la couleur, vous devez créer vos propres images d'étoiles avec des couleurs différentes, puis créer votre propre ressource XML dessinable et la transmettre à la classe RatingsBar en utilisant setProgressDrawable (Drawable d) ou l'attribut XML android: progressDrawable.

David
la source