Pasek oceny Androida zmienia kolory gwiazdek [zamknięte]


141

Jak mogę zmienić kolory i rozmiary gwiazd?


Myślę, że jeśli chcesz to zrobić, musisz stworzyć swój własny pasek oceny
Donal Rafferty

Napisałem wpis na blogu opisujący, jak zmienić obrazy RatingBar: kozyr.zydako.net/2010/05/23/pretty-ratingbar Pokazuje również, gdzie można określić rozmiar obrazu ...
kozyr

Miałem nadzieję, że to pytanie dotyczy wielokolorowego paska oceny, jak pokazano na stronach internetowych, nie mogłem znaleźć takiego dla siebie. Sam stworzyłem prostą implementację github.com/codebreaker/coloredratingbar-android . Mam nadzieję, że to komuś pomoże.
jaga

Odpowiedzi:


26

Krok # 1: Stwórz własny styl, klonując jeden z istniejących stylów (z $ANDROID_HOME/platforms/$SDK/data/res/values/styles.xml), umieszczając go w swoim własnym projekciestyles.xml i odwołując się do niego podczas dodawania widżetu do układu.

Krok # 2: Utwórz własne LayerDrawablezasoby XML RatingBardla paska, wskazując odpowiednie obrazy do wykorzystania w pasku. Oryginalne style wskażą Ci istniejące zasoby, z którymi możesz porównać. Następnie dostosuj swój styl, aby używać własnych LayerDrawablezasobów, a nie wbudowanych.


1
Zgodnie z krokiem 2, to nie działa w przypadku urządzeń Samsung 3 lub innych, nie jest to wymagane, aby było to LayerDrawable. Zobacz tutaj, aby uzyskać informacje: stackoverflow.com/questions/30266334/…
Kenny

6
Użyj androida: progressTint = "@ color / yellow". Zobacz odpowiedź @superpuccio.
Vincent

2
progressTint obsługiwana tylko powyżej poziomu 21 api
Yogesh Rathi


120

Na wspomnianym blogu jest to trochę skomplikowane, zastosowałem podobny, ale prostszy sposób. Potrzebujesz 3 obrazów gwiazdek (red_star_full.png, red_star_half.png i red_star_empty.png) i jednego pliku XML, to wszystko.

Umieść te 3 obrazy w res / drawable.

Umieść tam następującą ocenębar_red.xml:

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

i na koniec powiedz swojej definicji Ratingbar, aby używała tego, tj

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

Otóż ​​to.


3
Cześć Alex, wypróbowałem to rozwiązanie, ale kiedy próbuję ustawić ocenę na coś takiego jak 1,1, 1,2 itd ... wyświetla się jako 1,5. Zrobiłem 3-gwiazdkowe zdjęcia, jedno puste, w połowie pełne i jedno pełne. Przypuszczam, że ma interpolować między nimi, aby uzyskać ułamkowe składniki, po prostu zastanawiam się, czy ktoś inny miał ten sam problem, czy robię coś zauważalnie źle?
Graham Baitson,

Czy możesz mi powiedzieć o obrazach, których powinniśmy użyć pogoda, to kolorowe obrazy i rozmiar obrazów. Nie
jestem w

1
Wszyscy widzą odpowiedź na tę aktualizację 2015 poniżej! To dużo łatwiejsze i prostsze!
katie

Ta odpowiedź nadal zapewnia większą elastyczność w odniesieniu do różnych stanów gwiazd.
Tom Brinkkemper

Dlaczego pod gwiazdami pojawiają się pionowe linie? Próbowałem zdefiniować niestandardowy styl, określając wysokość, ale na moim AVD nadal widać pionowe linie pod gwiazdami.
Aleksandar

93

Spróbuj tego, jeśli chcesz tylko zmienić kolor:

RatingBar ratingBar = (RatingBar) findViewById(R.id.ratingBar);
LayerDrawable stars = (LayerDrawable) ratingBar.getProgressDrawable();
stars.getDrawable(2).setColorFilter(Color.YELLOW, PorterDuff.Mode.SRC_ATOP);

1
Co dokładnie PorterDuff.Mode.SRC_ATOPoznacza lub co robi?
Zapnologica

5
Nie działa na API 5.0 i nowszych. Potrzeby:Drawable stars = rb.getProgressDrawable(); stars.setTint( Color.YELLOW );
zyamys

@zyamys To naprawdę jest do bani = (Metoda dla „wyższych wersji” i inna metoda dla starszych wersji jest konieczna?
Daniela Morais

1
Działa tylko z dokładnością 0,5. W przeciwnym razie (precyzja <0,5) nakładka robi się dziwna i wydaje się, że niebieski kolor jest nadal z dokładnością 0,5, podczas gdy żółty jest dokładny
Teo Inke

1
Ostrzeżenie: awarie na urządzeniach sprzed lolipopu. Idź z zaakceptowaną odpowiedzią.
blockwala

70

Najłatwiejszy sposób, który u mnie zadziałał ... jeśli rozszerzasz działanie AppCompat

W pliku build.gradle dodaj najnowszą bibliotekę appcompat.

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

Rozszerz swoją aktywność na android.support.v7.app.AppCompatActivity

public class MainActivity extends AppCompatActivity {  
    ...
}

Zadeklaruj własny styl w pliku styles.xml.

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

Zastosuj ten styl do swojego RatingBar za pomocą atrybutu 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"/>

3
Dzięki @Vishal Kumar. Wypróbowałem to na Kitkat 4.4.4 (Samsung S3 neo) i Marshmallow 6.0.1 (Samsung Galaxy On Nxt), działało. Ale bez sukcesu na Lollipop 5.1 (Micromax). W przypadku Lollipopa użyłem atrybutu „android: progressTint” w RatingBar i tak, to działa.
Prashant,

To najlepsze rozwiązanie.
Arhat Baid

To powinna być wybrana poprawna odpowiedź.
Hampel Előd

1
To najlepsze rozwiązanie. Jeśli chcesz zmienić rozmiar gwiazdy, możesz użyć style="?android:ratingBarStyleSmall"razem.
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> i twoja ocenaBar android:theme="@style/RatingBarSmallTheme"
Zakhar Rodionov

47

Aktualizacja 2015

Teraz możesz użyć DrawableCompat do zabarwienia wszelkiego rodzaju rysunków. Na przykład:

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

Jest to zgodne wstecz do API 4


Nie zapomnij ustawić opcji drawable z powrotem na ratingBar.
zgrzytanie

15
To sprawia, że ​​cały element do rysowania na jeden kolor, co sprawia, że ​​puste gwiazdy są bardzo trudne do rozróżnienia.
blueice

Działa to tylko z biblioteką obsługi Androida> = 22, a nie z biblioteką wsparcia <22.
Raghav Sharma

2
Rysuje 5 kolorowych gwiazdek, a nie 3,5.
CoolMind

1
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {}
Otoczyłbym

38

Począwszy od API 21 , bardzo łatwo jest zmienić kolor gwiazd za pomocą tych trzech linii kodu:

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

Robiąc to w ten sposób, zmienisz:

  • kolor wypełnionych gwiazdek (progressTint)
  • kolor niewypełnionych gwiazdek (progressBackgroundTint)
  • oraz kolor obramowania gwiazd (wtórnyProgressTint)

Zamiast 3,5 maluje 4 gwiazdki.
CoolMind

@CoolMind ustawiono android: stepSize: 1 zamiast 0,5
eLemEnt

4
Jak zmienić kolor pustej gwiazdy?
winklerrr

@winklerrr, czy znalazłeś rozwiązanie, jak zmienić kolor pustej gwiazdy.
Tarun Kumar

Nie wykonałem dalszych kontroli, aby znaleźć rozwiązanie
winklerrr

36

Jeśli chcesz zmienić kolor wszystkich gwiazd, oświadczam, że ja używam:

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

Czy są sposoby na ustawienie koloru gwiazd na podstawie danych pobranych z bazy danych? Powiedzmy, że dostałem 5 gwiazdek, a dane zwrócone z bazy danych to 4. Więc zamiast zmieniać wszystkie 5, zmieniam tylko pierwsze 4

1
Funkcja getColor jest obecnie przestarzała, czy jest jakieś rozwiązanie alternatywne?
Manohar Reddy

2
Odpowiedzi można znaleźć tutaj stackoverflow.com/a/32202256/2513291 Na przykład to podejście ContextCompat.getColor (kontekst, R.color.nazwa_koloru)
Yuriy Vinogradov

działa dobrze, ale zauważ, że z jakiegoś powodu kolejność jest ważna (2, potem 1, potem 0). Próbowałem odwrotnie i przy pierwszej zmianie koloru doprowadziło to do pewnych usterek interfejsu użytkownika.
Simon Ninon,

25

Rozwiązania opublikowane przez Alexa i CommonsWares są poprawne. Jedną rzeczą, o której Android nigdy nie mówi, są odpowiednie rozmiary pikseli dla różnych gęstości. Oto wymagane wymiary dla każdej gęstości w oparciu o światło halo.

Mała gwiazda

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

Średnia gwiazda

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

Duża gwiazda

mdpi: 35px
hdpi: 52px
xhdpi: 69px
xxhdpi: 105px

czy mogę używać vectordrawble z gwiazdami
Mina Fawzy,

24

Tak więc zmagałem się z tym problemem przez dwie godziny i wymyśliłem działające rozwiązanie dla wszystkich wersji API, w których wyświetlane są również oceny w połowie gwiazdek.

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

Wywołujesz metodę z następującą kolejnością 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));

UWAGA: Musisz także określić atrybuty „max” i „numStars” w XML, w przeciwnym razie pół gwiazdki nie będą wyświetlane.


jedyny sposób, który działa dla mnie na API19, ale nie poddałem się, aby szukać sposobu na zrobienie tego z xml tylko T_T
Beeing Jk

@BeeingJk Jeśli utworzysz niestandardowy widok, który rozszerza RatingBar, możesz utworzyć własne atrybuty XML, aby określić kolor tinty. Masz wtedy pojedynczy punkt kontrolny do ustawiania tinty i możesz określić tintę w xml. Mam nadzieję, że to pomoże! W razie potrzeby mogę wyjaśnić więcej
Forrest Bice

Mode.SRC_INczy Mode.MULTIPLY?
Dr Jacky

12

Teraz możesz użyć DrawableCompat od AppCompat v22.1.0 i nowszych, aby dynamicznie zabarwić wszelkiego rodzaju elementy do rysowania, przydatne, gdy obsługujesz wiele motywów za pomocą jednego zestawu elementów do rysowania. Na przykład:

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

Jest to zgodne wstecz do API 4. Zobacz także wpis na blogu Chrisa Banesa na temat Support Libraries v22.1.0

Aby uzyskać rzeczywisty rozmiar i kształt, musisz zdefiniować nowy styl i elementy rysunkowe listy warstw dla odpowiedniego rozmiaru, tak jak inni już odpowiedzieli powyżej.


Drawables nie są tablicami. Jak uzyskujesz dostęp do postępu [0]?
blueice

@blueice Masz rację, przepraszam, Drawable powinno być LayerDrawable, poprawione teraz, dzięki.
Dan Dar3,

Nadal nie wydawało mi się to działać, skończyło się na tym, co Jurij Winogradow udzielił innej odpowiedzi na to pytanie i wydaje się, że działa.
blueice

Jak zmienić zamiast tego do rysowania Zmienić kolor?
Iman Marashi

@ImanMarashi Zobacz odpowiedź Alexa opartą na XML powyżej, LayerDrawable.setDrawable (indeks, rysowalny) jest dostępny tylko od API23.
Dan Dar3

10

Posługiwać się android:theme atrybutu:

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

9

Aby zmienić kolor paska oceny z xml: -

android:progressTint="@color/your_color"
android:backgroundTint="@color/your_color"
android:secondaryProgressTint="@color/your_color"

nie zmienia koloru pustej gwiazdy
Nainal

7

Aby zmienić kolor wystarczy ustawić parametr 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"
       />

W przypadku rozmiaru właściwość style.


działa tylko na API 21 lub nowszym, dzięki
Junaid

5

Najprostszy sposób:

android:progressTint="@color/color"

1
Zauważ, że działa to tylko na api 21+
Ixx

4

Budynek @ lgvalle's odpowiedź.

Aktualizacja 2015

Teraz możesz użyć DrawableCompat do zabarwienia wszelkiego rodzaju rysunków. Na przykład:

Drawable progress = ratingBar.getProgressDrawable (); DrawableCompat.setTint (postęp, Color.WHITE); Jest to zgodne wstecz do 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));

Pozwoli to zachować kolory kroków ułamkowych.


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

użyj własnego koloru


4

Bez dodawania nowego stylu możesz użyć odcienia w pliku 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"/>

3

Działa na Androida poniżej i powyżej wersji 21

Po kilku badaniach wymyśliłem tę metodę ustawiania odcienia tła, odcienia przerwy (np .: pół gwiazdki) i koloru odcienia gwiazdy.

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

3

Proste rozwiązanie, użyj AppCompatRatingBar i jego metody setProgressTintList , aby to osiągnąć, zobacz tę odpowiedź w celach informacyjnych.


To działało dla mnie pod API 28 przy użyciu com.google.android.material: materiał: 1.1.0-alpha02
Mark Lapasa,

2

Rozwiązuję ten problem w następujący sposób:

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

Dzięki, działa. Ale w przypadku oceny ułamkowej gwiazdki są pomalowane w całości.
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);

dla mnie to działa ...



1

Korzystając z powyższych odpowiedzi, stworzyłem szybką statyczną metodę, którą można łatwo ponownie wykorzystać. Ma na celu jedynie zabarwienie koloru postępu dla aktywowanych gwiazd. Gwiazdy, które nie są aktywowane, pozostają szare.

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

Po prostu przekaż swój pasek oceny i kolor, używając getResources().getColor(R.color.my_rating_color)

Jak widać, używam DrawableCompat, więc jest kompatybilny wstecz.

EDYCJA: Ta metoda nie działa na API21 (zobacz dlaczego). Kończy się z NullPointerException podczas wywoływania setProgressBar. Skończyło się na wyłączeniu całej metody na API> = 21.

Dla API> = 21 używam rozwiązania SupperPuccio.


java.lang.ClassCastException: android.support.v4.graphics.drawable.DrawableWrapperHoneycomb nie może być rzutowany na android.graphics.drawable.LayerDrawable on pre-Lollipop
Ishaan Garg

1
@IshaanGarg masz rację. Napotkałem ten sam problem i zaktualizowałem moją metodę. Zaktualizowałem kod, aby obsłużyć sprawę. Nie sądzę, że to kwestia wersji Androida. Jeśli używasz mniejszej wersji paska oceny (ze style = "? Android: attr / ratingBarStyleSmall"), wówczas zwracany element do rysowania jest nadal LayoutDrawable.
JDenais

Tak, właśnie to, co zaimplementowałem, po prostu pamiętaj, aby użyć AppCompatRatingBar. Chociaż nie jestem w stanie uzyskać pół gwiazdki podczas wstępnego ustawiania oceny z XML / java. Podobnie jak setRating (3.5) pokazuje 4 pełne gwiazdki
Ishaan Garg

1

Pasek oceny jest używany automatycznie w czasie wykonywania do zmiany koloru gwiazdy dotykowej.

Najpierw dodaj styl w pliku 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>

Następnie do paska oceny dodaj motyw w następujący sposób:

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

0

1) zadeklaruj ten plik 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) w 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) ocena aktywna - weź dowolny obraz w ciemnym kolorze, ponieważ będzie on używany jako przezroczystość koloru dla innej oceny

rating_inactive - zrób dowolne zdjęcie tego samego rozmiaru z powyższego obrazu na jasnym tle. Będzie używane, gdy nie zostanie wybrana ocena


0

Bardzo prostym sposobem zmiany koloru obramowania gwiazd jest użycie parametru xml:

android:progressBackgroundTint=""

w widoku RatingBar. Wartość powinna być kodem szesnastkowym koloru.


Nie wiem czemu, ale wygląda na to, że metoda wpływa tylko na obramowanie gwiazd (kolor wypełnienia pozostaje kolorem domyślnym)
superpuccio.

Ok, przegapiłeś niektóre parametry xml. Sprawdź moją odpowiedź poniżej.
superpuccio

1
Masz rację. Nie wiem, dlaczego myślałem, że miał problemy ze zmianą koloru obramowania gwiazdy (może dlatego, że miałem problem). Twoja odpowiedź jest bardziej kompletna.
Pau Arlandis Martinez

0

Szukałem niezawodnej metody, aby to zrobić, aż do co najmniej API 9. Rozwiązanie „Casting do LayerDrawble” wydawało mi się ryzykownym rozwiązaniem, a kiedy przetestowałem je na telefonie z Androidem w wersji 2.3, zostało ono pomyślnie przesłane, ale wywołanie DrawableCompat.setTint (...) nie przyniosło żadnego efektu.

Konieczność ładowania majątku trwałego również nie wydawała mi się dobrym rozwiązaniem.

Zdecydowałem się napisać własne rozwiązanie, które jest rozszerzeniem klasy AppCompatRatingBar, używając niestandardowego Drawable, który programowo rysuje gwiazdy. Działa idealnie na moje potrzeby, opublikuję to na wypadek, gdyby komuś pomogło:

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

Link jest łatwiejszy, ponieważ możesz pobrać pełny plik bezpośrednio, ale tutaj jest pełny kod na wszelki wypadek:

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

0

Trochę późna odpowiedź, ale mam nadzieję, że pomoże to niektórym ludziom.

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

A oto jak wygląda WhiteRatingStar

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

Dzięki temu gwiazdy będą na przykład zabarwione na biało.



-1

Jak sugeruje poprzednia odpowiedź, zmiana koloru paska oceny nie jest łatwa. Gwiazdy nie są rysowane programowo, są to obrazy o stałym rozmiarze i określonych gradientach kolorów. Aby zmienić kolor, musisz utworzyć własne obrazy gwiazd z różnymi kolorami, a następnie przystąp do tworzenia własnego zasobu XML, który można rysować, i przekaż go do klasy RatingsBar za pomocą setProgressDrawable (Drawable d) lub atrybutu XML android: progressDrawable.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.