Change the shape color of a ImageButton
Asked Answered
N

1

0

I have a recyclerView where I create 12 ImageButtons. As default they are all black colored, because I made a custom shape for the imageButton that have a black solid color. The custom shape is set as the imageButtons background

The shape:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners
    android:radius="5.3dp"/>
<solid
    android:color="#000000"/>


</shape>

This is how the ImageButtons look like now. But they all have the same color, which is not what I want.

enter image description here

I want dynamically to give each ImageButton a different color from my color-array in my color.xml. I have tried many of the solution of how to change the solid color of a shapes but none of them have worked.

Method that creates 12 imageButton for the recyclerView:

 public static List<ColorButton> initColorButtons(){

    colorButtonList = new ArrayList<>();

    //here we retrive all colors from color.xml
    Resources resources = App.getAppContext().getResources();
    String colors[] = resources.getStringArray(R.array.backgroundcolors);

        for(int i=0; i<colors.length; i++){

        //Creates 12 ImageButtons with a custom shape
        colorButtonList.add(new ColorButton(new ImageButton(App.getAppContext()), colors[i]));


        //Here each imagebutton should get its own color.
        Drawable drawable = colorButtonList.get(i).getButton().getBackground();

        if (colorButtonList.get(i).getButton().getBackground() instanceof GradientDrawable) {

            GradientDrawable gd = (GradientDrawable) drawable.getCurrent();
            gd.setColor(Color.parseColor(colors[i]));

    }
}
    return colorButtonList;
}

The Imagebutton that is created for the recyclerView. The @drawable/bbtn shapes backgrundcolor is set to black as default

<?xml version="1.0" encoding="utf-8"?>
<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/colorbutton"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="7dp"
android:layout_marginTop="25dp"
android:layout_marginBottom="25dp"
android:background="@drawable/bbtn">

</ImageButton>

Here are the color-array. Each button should have a different background color of one of the list:

  <string-array name="backgroundcolors">
    <item>#000000</item>
    <item>#ffffff</item>
    <item>#373737</item>
    <item>#e6e6e6</item>
    <item>#EAE1D8</item>
    <item>#fd79a1</item>
    <item>#E849A1</item>
    <item>#ff0f68</item>
    <item>#c22032</item>
    <item>#F7E84E</item>
    <item>#0d4b7e</item>
    <item>#329de7</item>
    <item>#68be3f</item>
    <item>#006c35</item>
    <item>#395a4f</item>
    </string-array>

This is the class where I create ImageButtons

public class ColorButton{

private ImageButton button;
private String color;
public static List<ColorButton> colorButtonList;


public ColorButton(ImageButton button, String color) {
    this.button = button;
    this.color = color;
}

public String getColor() {
    return color;
}

public void setColor(String color) {
    this.color = color;
}

public ImageButton getButton() {
    return button;
}

@SuppressLint("NewApi")
public static List<ColorButton> initColorButtons(){
    colorButtonList = new ArrayList<>();

    //here we retrive all colors from color.xml
    Resources resources = App.getAppContext().getResources();
    String colors[] = resources.getStringArray(R.array.backgroundcolors);

    for(int i=0; i<colors.length; i++){
        //Creates 12 ImageButtons with a custom shape
        colorButtonList.add(new ColorButton(new ImageButton(App.getAppContext()), colors[i]));

        //Here each imagebutton should get its own color.
        Drawable drawable = colorButtonList.get(i).getButton().getBackground();

        if (drawable instanceof GradientDrawable) {
            GradientDrawable gd = (GradientDrawable) drawable.getCurrent();
            gd.setColor(Color.parseColor(colors[i]));
        } else if (drawable instanceof RippleDrawable) {
            RippleDrawable rd = (RippleDrawable) drawable;
            // keep in mind that colors[i] should be a string with the hex representation of a color, like: #F4F4F4
            int color = Color.parseColor(colors[i]);
            rd.setColor(newColorStateList(color));
        }
    }
    return colorButtonList;
}


private static ColorStateList newColorStateList(int color) {
    int[][] states = new int[][] {
            new int[] { android.R.attr.state_enabled}, // enabled
            new int[] {-android.R.attr.state_enabled}, // disabled
    };

    int[] colors = new int[] {
            color, color
    };

    return new ColorStateList(states, colors);
}

}

This is from my recyclerView Adapter class where I infalte layout.item_colorbutton. <- this is at the top of this post

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    Context context = parent.getContext();
    LayoutInflater inflater = LayoutInflater.from(context);

    //inflates the custom layout for a button
    View colorButtonView = inflater.inflate(R.layout.item_colorbutton, parent, false);

    //Return a new holder instance of a colorButton
    ViewHolder viewHolder = new ViewHolder(colorButtonView);
    return viewHolder;
}
Noetic answered 14/2, 2016 at 22:14 Comment(0)
S
2

Your problem is that in your case getBackground() is returning a RippleDrawable, not a GradientDrawable. Both extend Drawable, but you can not cast one to the other. Try this:

public List<ImageButton> initColorButtons(){
    colorButtonList = new ArrayList<>();

    //here we retrive all colors from color.xml
    Resources resources = App.getAppContext().getResources();
    String colors[] = resources.getStringArray(R.array.backgroundcolors);

    for(int i=0; i<colors.length; i++){
        //Creates 12 ImageButtons with a custom shape
        colorButtonList.add(new ColorButton(new ImageButton(App.getAppContext()), colors[i]));

        //Here each imagebutton should get its own color.
        Drawable drawable = colorButtonList.get(i).getBackground();

        if (drawable instanceof GradientDrawable) {
            GradientDrawable gd = (GradientDrawable) drawable.getCurrent();
            gd.setColor(Color.parseColor(colors[i]));
        } else if (drawable instanceof RippleDrawable) {
            RippleDrawable rd = (RippleDrawable) drawable;
            // keep in mind that colors[i] should be a string with the hex representation of a color, like: #F4F4F4
            int color = Color.parseColor(colors[i]);
            rd.setColor(newColorStateList(color));
        }
    }
    return colorButtonList;
}

private ColorStateList newColorStateList(int color) {
    int[][] states = new int[][] {
            new int[] { android.R.attr.state_enabled}, // enabled
            new int[] {-android.R.attr.state_enabled}, // disabled
    };

    int[] colors = new int[] {
            color, color
    };

    return new ColorStateList(states, colors);
}

Result:

screenshot

You can read more on how to create a ColorStateList in this SO question.

EDIT: In order to correctly modify the buttons you create with the method onCreateViewHolder, you need to implement onBindViewHolder in your Adapter and change the color of your buttons there.

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
        Drawable drawable = holder.getBackground();

        if (drawable instanceof GradientDrawable) {
            GradientDrawable gd = (GradientDrawable) drawable.getCurrent();
            gd.setColor(Color.parseColor(colors[position]));
        } else if (drawable instanceof RippleDrawable) {
            RippleDrawable rd = (RippleDrawable) drawable;
            int color = Color.parseColor(colors[position]);
            rd.setColor(newColorStateList(color));
        }
}
Sadirah answered 15/2, 2016 at 0:45 Comment(13)
The app dosn't crash anymore but my ImageButton stil have black color. I want them all to have a different color at runtime. I dont want anything of ColorStateList at all.Each ImageButton must have its own color from my colors[i] which contain different colors.Noetic
ColorStateList is needed to change the colors in RippleDrawable. Please, update your question showing how you are creating the ColorStateList so I can help you.Sadirah
@Muddz you need to add the else if (drawable instanceof RippleDrawable) { RippleDrawable rd = (RippleDrawable) drawable; rd.setColor(yourColorStateList); } part in order for it to work, and to create a proper ColorStateListSadirah
Hi. Since the last array: colors, is a String it didn't accept it, because it need a int array. So I modified it quick to:int[] states2 = new int[]{ Color.BLACK, Color.BLUE, Color.CYAN, Color.BLACK, Color.BLUE, Color.CYAN, Color.BLACK, Color.BLUE, Color.CYAN,Color.CYAN,Color.CYAN }; But nothing happend with the colors. all button is still blackNoetic
@Muddz Updated answer correcting the ColorStateList creation. It's working for me.Sadirah
Could you post a link to a screenshot of it? And I have copied the code at maked it work and nothing crashes but still the buttons color dont change..Noetic
I have posted the color.xml where I store my color-arrayNoetic
@Muddz I added screenshot using your color-array. I'm seeing that you deleted the Colorlist part of your code, you shouldn't. Is not going to work for you without that. Also, can you please provide the implementation of ColorButton, and show where you assign the first shape background to the button.Sadirah
Dayum It works with you as it should! Its frustating it dosn't work here. I have posted the whole class so you can se what I'm doing.Noetic
Ok, so the problem is in your Adapter. When you do View colorButtonView = inflater.inflate(R.layout.item_colorbutton, parent, false); you are creating a new ImageButton, which has the it's shape color in black and this is what you see in screen. I'll add code to my answer to show you how to user the onBindViewHoldermethod.Sadirah
Amazing! It worked!! so beautiful! You're are geniues man! Thank you for your time!!!Noetic
Is it possible to set an image as a background for imageButton in index 0 instead of a solid color? I have tried for many hours without succses! I'm out of ideasNoetic
@Muddz yes, it's possible (using the src xml attribute or setImageResource method). However, you might want to ask it in a separate question so we don't flood this question with unrelated comments.Sadirah

© 2022 - 2024 — McMap. All rights reserved.