I am trying to flash different colours onto the screen at regular intervals (a few times per second).
To change the colours, I use Drawable.setColorFilter(int color, Mode mode) on the background of my main view:
myView.getBackground().setColorFilter(Color.RED, PorterDuff.Mode.SRC);
For debugging purposes, I added another view that I change using View.setBackgroundColor(int color).
The problem is that the setColorFilter() calls are working on Lollipop, but are broken on previous versions (specifically Nexus 7 v4.4.4, Galaxy Nexus v4.2.1).
I call the colour changing code inside a Runnable that is triggered at regular intervals by a Handler.
The handler is being called on all platforms (I can see the background changes due to the debugging setBackgroundColor() calls).
Below is the colour cycling code:
Handler mHandler;
RunnableOnTick thisRunnable;
View vDebug;
View vBroken;
class RunnableOnTick implements Runnable
{
int backgroundColor;
#Override
public void run()
{
color = random.nextInt(2);
switch (color)
{
case 0:
{
backgroundColor = Color.RED;
break;
}
case 1:
{
backgroundColor = Color.GREEN;
break;
}
}
// this works on all platforms
vDebug.setBackgroundColor(backgroundColor);
// this works only on Lollipop
vBroken.getBackground().setColorFilter(backgroundColor, PorterDuff.Mode.SRC);
vBroken.invalidate();
mHandler.postDelayed(thisRunnable, 100);
}
}
I have tried different PorterDuff.Mode values - still can't get it working on Android 4.
What is different between Android v4 and v5 that would change the way setColorFilter() works?
Ultimately, it seems like the problem is that KitKat doesn't support using a ColorFilter (or implicitly an alpha) on a Drawable that will in turn be in a StateListDrawable. My solution was to use the same to code to construct the complex Drawable and then render that into a simple BitMapDrawable:
static Drawable createDrawable(Context context, int color, boolean disabled) {
OvalShape oShape = new OvalShape();
ShapeDrawable background = new ShapeDrawable(oShape);
background.getPaint().setColor(color);
ShapeDrawable shader = new ShapeDrawable(oShape);
shader.setShaderFactory(new ShapeDrawable.ShaderFactory() {
#Override
public Shader resize(int width, int height) {
return new LinearGradient(0, 0, 0, height,
new int[]{
Color.WHITE,
Color.GRAY,
Color.DKGRAY,
Color.BLACK
}, null, Shader.TileMode.REPEAT);
}
});
Drawable icon = ContextCompat.getDrawable(context, R.drawable.ic_chat_button).mutate();
icon.setColorFilter(context.getResources().getColor(R.color.control_tint_color), PorterDuff.Mode.SRC_IN);
Drawable layer = new LayerDrawable(new Drawable[]{ shader, background, icon });
layer.setAlpha(disabled ? 128 : 255);
// Note that on KitKat, setting a ColorFilter on a Drawable contained in a StateListDrawable
// apparently doesn't work, although it does on later versions, so we have to render the colored
// bitmap into a BitmapDrawable and then put that into the StateListDrawable
Bitmap bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
layer.setBounds(0, 0, layer.getIntrinsicWidth(), layer.getIntrinsicHeight());
layer.draw(canvas);
return new BitmapDrawable(context.getResources(), bitmap);
}
There's an issue in AppCompat with compound Drawable below API 21 that me thinks is related:
https://code.google.com/p/android/issues/detail?id=191111
The simple solution is not using drawables from XML but create them in code and then apply setColorFilter. That's why #Hardeep solution worked.
Fun trivia: In my case setColorFilter on XML-created TextView drawableLeft worked fine, but only when invoked via click handler / delayed. When invoked in onCreate / onResume etc nothing happened.
I had the same issue on pre-lollipop, I solved replacing:
vBroken.getBackground().setColorFilter(backgroundColor, PorterDuff.Mode.SRC);
with:
Drawable d = vBroken.getBackground();
d.setColorFilter(backgroundColor, PorterDuff.Mode.MULTIPLY);
vBroken.setBackground(d);
For me, a ColorFilter would not be applied to a color item in a StateListDrawable.
Creating a Drawable to represent that color and using that instead in the StateListDrawable saw setColorFilter working on pre-Lollipop devices I tested.
As a side note, I made a pure white Drawable so that tinting color would be applied at full opacity.
Have you tried directly like this?!
vBroken.getBackground().setColorFilter(Color.argb(255, 255, 255, 255),PorterDuff.Mode.MULTIPLY));
In order to paint drawable for as many different states as you want on all android versions, you can use this helper class:
public class MagicDrawable extends StateListDrawable {
private Map<Integer, Integer> stateColorsMap;
private int defaultColor;
public static MagicDrawable create(Drawable drawable, int defaultColor, int pressedColor, int selectedColor){
Map<Integer, Integer> map = new HashMap();
map.put(android.R.attr.state_selected, selectedColor);
map.put(android.R.attr.state_pressed, pressedColor);
MagicDrawable stateDrawable = new MagicDrawable(drawable, defaultColor, map);
return stateDrawable;
}
public static MagicDrawable createSelected(Drawable drawable, int defaultColor, int selectedColor){
Map<Integer, Integer> map = new HashMap();
map.put(android.R.attr.state_selected, selectedColor);
MagicDrawable stateDrawable = new MagicDrawable(drawable, defaultColor, map);
return stateDrawable;
}
public static MagicDrawable createPressed(Drawable drawable, int defaultColor, int pressedColor){
Map<Integer, Integer> map = new HashMap();
map.put(android.R.attr.state_pressed, pressedColor);
MagicDrawable stateDrawable = new MagicDrawable(drawable, defaultColor, map);
return stateDrawable;
}
/**
* Create state list drawable programmatically - just pass drawable, default color of drawable, and Map of (state , color)
* #param drawable resourse for icons
* #param defaultColor color for normal state
* #param stateColorsMap map of for ex. android.R.attr.state_pressed and ColorManager.someColor
*
* Map<Integer, Integer> map = new HashMap<>();
map.put(android.R.attr.state_pressed, ColorManager.rose);
*/
public MagicDrawable(Drawable drawable, int defaultColor, Map<Integer, Integer> stateColorsMap) {
super();
this.stateColorsMap = stateColorsMap;
this.defaultColor = defaultColor;
drawable.setColorFilter(defaultColor, PorterDuff.Mode.SRC_IN);
if (stateColorsMap != null) {
for (int state : stateColorsMap.keySet()) {
addState(new int[]{state}, drawable);
}
}
addState(new int[] {}, drawable);
}
#Override
protected boolean onStateChange(int[] states) {
if (stateColorsMap == null) {
super.setColorFilter(defaultColor, PorterDuff.Mode.SRC_IN);
return super.onStateChange(states);
}
boolean colorSet = false;
for (int state : states) {
for (int st : stateColorsMap.keySet()){
if (state == st) {
super.setColorFilter(stateColorsMap.get(st), PorterDuff.Mode.SRC_IN);
colorSet = true;
break;
}
}
}
if (!colorSet) {
super.setColorFilter(defaultColor, PorterDuff.Mode.SRC_IN);
}
return super.onStateChange(states);
}
#Override
public boolean isStateful() {
return true;
}
}
/**
* Tint / Colorise the Supplied {#code drawable} into another color of supplied {#code colorResId}
* #param context
* #param drawable
* #param colorResId
* #return
*/
public Drawable tintThisDrawable(Context context ,Drawable drawable,#ColorRes int colorResId)
{
Resources res = context.getResources();
int color = res.getColor(colorResId);
if (drawable != null) {
drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
}
return drawable;
}
I remember this function working somewhere in my Project. Please test this yourself.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
How can I change the star colors and size of the stars?
It's a little complicated at the mentioned blog, I've used a similar but simplier way.
You do need 3 star images (red_star_full.png, red_star_half.png and red_star_empty.png) and one xml, that's all.
Put these 3 images at res/drawable.
Put there the following ratingbar_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>
and, finally, tell your ratingbar definition to use this, i.e.
<RatingBar android:progressDrawable="#drawable/ratingbar_red"/>
That's it.
Try this, if you only want to change color:
RatingBar ratingBar = (RatingBar) findViewById(R.id.ratingBar);
LayerDrawable stars = (LayerDrawable) ratingBar.getProgressDrawable();
stars.getDrawable(2).setColorFilter(Color.YELLOW, PorterDuff.Mode.SRC_ATOP);
The easiest way that worked for me...if you are extending AppCompat Activity
In your build.gradle add latest appcompat library.
dependencies {
compile 'com.android.support:appcompat-v7:X.X.X' // where X.X.X version
}
Make your activity extend android.support.v7.app.AppCompatActivity
public class MainActivity extends AppCompatActivity {
...
}
Declare custom style in your styles.xml file.
<style name="RatingBar" parent="Theme.AppCompat">
<item name="colorControlNormal">#color/indigo</item>
<item name="colorControlActivated">#color/pink</item>
</style>
Apply this style to your RatingBar via android:theme attribute.
<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"/>
From the API 21 on it's very easy to change the color of the stars with this three lines of code:
android:progressTint="#android:color/holo_red_dark"
android:progressBackgroundTint="#android:color/holo_red_dark"
android:secondaryProgressTint="#android:color/holo_red_dark"
Doing it like this, you'll change:
the filled stars color (progressTint)
the unfilled stars color (progressBackgroundTint)
and the border color (secondaryProgressTint) of the stars
2015 Update
Now you can use DrawableCompat to tint all kind of drawables. For example:
Drawable progress = ratingBar.getProgressDrawable();
DrawableCompat.setTint(progress, Color.WHITE);
This is backwards compatible up to API 4
If you want to change color for all stars states you my use:
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);
Step #1: Create your own style, by cloning one of the existing styles (from $ANDROID_HOME/platforms/$SDK/data/res/values/styles.xml), putting it in your own project's styles.xml, and referencing it when you add the widget to a layout.
Step #2: Create your own LayerDrawable XML resources for the RatingBar, pointing to appropriate images to use for the bar. The original styles will point you to the existing resources that you can compare with. Then, adjust your style to use your own LayerDrawable resources, rather than built-in ones.
The solutions that Alex and CommonsWares have posted are correct. One thing that the Android never talks about though is proper pixel sizes for different densities. Here are the required dimensions for each density based on halo light.
Small Star
mdpi: 16px
hdpi: 24px
xhdpi: 32px
xxhdpi: 48px
Medium Star
mdpi: 24px
hdpi: 36px
xhdpi: 48px
xxhdpi: 72px
Large Star
mdpi: 35px
hdpi: 52px
xhdpi: 69px
xxhdpi: 105px
So I have been struggling with this issue for two hours and I have come up with a working solution for all API versions, where half stars ratings are also shown.
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);
}
}
You call the method with this order of 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));
NOTE: Also you must specify attributes "max" and "numStars" in XML, otherwise half stars aren't shown.
Now you can use DrawableCompat from AppCompat v22.1.0 onwards to dynamically tint all kind of drawables, useful when you're supporting multiple themes with a single set of drawables. For example:
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
This is backwards compatible down to API 4. Also see Chris Banes' blog post on Support Libraries v22.1.0
For the actual size and shape you will need to define a new style and layer-list drawables for the appropriate size, as others have already answered above.
For just changing the color of Rating bar from xml:-
android:progressTint="#color/your_color"
android:backgroundTint="#color/your_color"
android:secondaryProgressTint="#color/your_color"
Use android:theme attribute:
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" />
To change the color you just have to put set the parameter 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"
/>
For the size the style property.
The simpliest way:
android:progressTint="#color/color"
Withou adding a new style you can use the tint color within the 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"/>
Building #lgvalle's answer.
2015 Update
Now you can use DrawableCompat to tint all kind of drawables. For example:
Drawable progress = ratingBar.getProgressDrawable();
DrawableCompat.setTint(progress, Color.WHITE);
This is backwards compatible up to 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));
This will keep the fraction steps colors.
<!--For rating bar -->
<style name="RatingBarfeed" parent="Theme.AppCompat">
<item name="colorControlNormal">#color/colorPrimary</item>
<item name="colorControlActivated">#color/colorPrimary</item>
</style>
use your own color
Works for Android below and above version 21
After some research I've come up with this method to set the background tint, the gap tint (ex: half star) and the star tint color.
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
Simple solution, use AppCompatRatingBar and its setProgressTintList method to achieve this, see this answer for reference.
I solve this issue this following:
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);
RatingBar mRating=(RatingBar)findViewById(R.id.rating);
LayerDrawable layerDrawable=(LayerDrawable)mRating.getProgressDrawable();
layerDrawable.getDrawable(2).setColorFilter(Color.parseColor
("#32CD32"), PorterDuff.Mode.SRC_ATOP);
for me its working....
I found a simple solution for changing the color of the star according to your theme.
Goto this site : http://android-holo-colors.com/
Choose your theme color and get your star images created.
Using the answers above, I created a quick static method that can easily be re-used. It only aims at tinting the progress color for the activated stars. The stars that are not activated remain grey.
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;
}
}
Just pass your rating bar and a Color using getResources().getColor(R.color.my_rating_color)
As you can see, I use DrawableCompat so it's backward compatible.
EDIT : This method does not work on API21 (go figure why). You end up with a NullPointerException when calling setProgressBar. I ended up disabling the whole method on API >= 21.
For API >= 21, I use SupperPuccio solution.
The rating bar is used automatically at run time for change color on touch star.
First add style in app\src\main\res\values\styles.xml file:
<style name="RatingBar" parent="Theme.AppCompat">
<item name="colorControlNormal">#android:color/darker_gray</item>
<item name="colorControlActivated">#color/com_facebook_blue</item>
</style>
Then your rating bar add theme like this:
<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"/>
1) declare this 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) in 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) rating active---take any image with dark color coz it will be used as color transparency for different rating
rating_inactive--take any image of same size of above image with light background..it will used when no rating is selected
A very easy way to change the border colour of the stars is using the xml parameter:
android:progressBackgroundTint=""
in the ratingBar view. The value should be a hexadecimal code for a color.
I was looking for a reliable method to do this all the way down to API 9 at least.
The "casting to LayerDrawble" solution seemed like a risky solution to me, and when I tested it out on an Android phone on 2.3, it casted successfully but the call to DrawableCompat.setTint(...) did not have any effect.
The need to load drawable assets did not seem like a good solution to me either.
I decided to code my own solution which is a class extending AppCompatRatingBar, using a custom Drawable taking care of drawing the stars programmatically. It works perfectly for my needs, I'll post it in case it helps anyone:
https://gist.github.com/androidseb/2b8044c90a07c7a52b4bbff3453c8460
The link is easier because you can get the full file directly, but here is the full code just in case:
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;
}
}
}
A bit late answer but i hope it will help some folks.
<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" />
And here is what the WhiteRatingStar looks like
<style name="WhiteRatingStar" parent="Base.Widget.AppCompat.RatingBar.Small">
<item name="colorAccent">#android:color/white</item>
</style>
With this the stars will be coloured in white for example.
Use this link
Android RatingBar change star colors
set your style inside value/style(v-21);
As the previous answer implies, it is not easy to change the color of the ratingbar. The stars are not programmatically drawn, they are images with fixed size and specific color gradients. To change the color you have to create your own star images with different colors then proceed to create your own drawable XML resource and pass it to the ratingsBar class using setProgressDrawable(Drawable d) or XML attribute android:progressDrawable.