Defined custom shape for button in xml. Now I want to change the color dynamically. How?
Asked Answered
P

3

1

I have this:

round_button.xml

<xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
    <shape android:shape="oval">
        <solid android:color="#dec60000"/>
        <size android:width="150dp" android:height="150dp"/>
    </shape>
</item>
<item android:state_pressed="false">
    <shape android:shape="oval">
        <solid android:color="#860000"/>
        <size android:width="150dp" android:height="150dp"/>
    </shape>
</item>

My Button:

 <Button
        android:id="@+id/incrementBTN"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:background="@drawable/round_button"
        android:onClick="onClick"
        android:soundEffectsEnabled="true"
        android:text="0"
        android:textSize="50sp"
        tools:ignore="HardcodedText" />

Dynamically, I want to change the background color (which is defined in the round_button xml) programmatically. Is there a way I can do this?

Papst answered 21/10, 2016 at 19:7 Comment(6)
I believe not. If you change the color, it will replace the background. Whatever color you want to change to, you have to have a second XML with the different color and you can change to that XML as background in JavaElmerelmina
@th3pat3l Wow. Bravo Google, it's very simple to do things with your SDK.Papst
are you trying to change the background color for a specific event? For example, when the button is clicked, when the button is focused or if the button is hovered upon? What's the actual use?Elmerelmina
@th3pat3l I am getting the dominant color of the background image, then setting that color to the buttonPapst
I believe this post is doing what you want: Change drawable color programmaticallyBalfore
@S.Vincent I'll try that...Papst
P
1

I solved it by setting a ColorFilter:

Drawable mDrawable = context.getResources().getDrawable(R.drawable.balloons); 
mDrawable.setColorFilter(new PorterDuffColorFilter(0xffff00,PorterDuff.Mode.MULTIPLY));
myButton.setResource(mDrawable);
Papst answered 22/10, 2016 at 5:20 Comment(0)
P
2

If you want to define certain states for your button, you could set them all in xml, without having to do it programmatically (if you do, you can indeed set a filter, but it can get messy if you have many states and conditions IMO).

I'll detail the steps here:

1) Creating a xml with the states you want

You can create a xml with a selector in your drawable folder with the defined states. As an example,

button_bkg.xml

<?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@drawable/bkg_is_pressed" android:state_pressed="true"/>
        <item android:drawable="@drawable/bkg_is_disabled" android:state_enabled="false"/>
        <item android:drawable="@drawable/bkg_default"/>
</selector>

Let's call this file button_bkg.xml. In the example above, I have listed 3 states: pressed, disabled and default, which means that, when the button is pressed, it will assume the bkg_is_pressed background and, when I set the button to disabled (either in xml or programmatically through setEnabled(boolean), it will assume bkg_is_disabled background.

2) Creating the backgrounds

Now you will define what you want the background to be in the xml files you defined (bkg_is_pressed, bkg_is_default, bkg_is_pressed). In your case, in example, you would take each shape defined in your round_button.xml file and separate them into each one of the xml files you defined for the states. In my case, I defined a layer-list:

bkg_is_pressed.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
    <shape android:shape="rectangle">
            <corners android:radius="@dimen/button_corner_radius"/>
            <solid android:color="@color/color_alert"/>
            <stroke
                 android:width="@dimen/universal_1_pixel"
                    android:color="@color/color_gray_dark"/>
        </shape>
    </item>
    <item>
        <shape android:shape="rectangle">
            <corners android:radius="@dimen/button_corner_radius"/>
            <solid android:color="@color/color_mask_highlighted"/>
        </shape>
    </item>
</layer-list>

You will do that for each of the states.

It is important to note that, if you are going to build for API 21+, you can define a ripple effect by creating ANOTHER button_bkg.xml file in your drawables-v21 folder, which would be like this:

button_bkg.xml (in your drawable-v21 folder)

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/bkg_is_disabled" android:state_enabled="false" />
    <item android:drawable="@drawable/bkg_is_pressed" />

To use the ripple, you can define a color as explained below:

bkg_is_pressed.xml (in your drawable-v21 folder)

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/color_mask_highlighted">
    <item android:drawable="@drawable/bkg_is_default" />
</ripple>

You only have to put the button_bkg.xml and the bkg_is_pressed.xml into your drawable-v21 folder file. In my case, bkg_is_default and bkg_is_disabled.xml were the same for both 21+ and 21- APIs, so I didn't add it to my drawable-v21 folder, I just created it in the drawable folder.

I want to emphasize that you STILL need the other files in your regular drawable folder so that devices with API 21- will work properly.

3) Assigning that background to your button

Lastly, you just have to define that background to your button:

<Button
    ...
    android:background="@drawable/button_bkg
/>

So, there you have it. This way, you don't need to set the styles programmatically, you can just define all the backgrounds (according to your states) in the xml files. But, if you also prefer to set them all programmatically, you can do the same, just use setBackground and use the xml files you defined and apply the state logic you want to it (if button is pressed, setBackground(bkg_is_pressed) and so on)

I hope that helps, let me know if that works for you.

Portable answered 22/10, 2016 at 21:40 Comment(1)
@AbAppletic What do you think about my example, was it useful for you? If it was, remember to upvote it for future reference : ) Cheers!Portable
P
1

I solved it by setting a ColorFilter:

Drawable mDrawable = context.getResources().getDrawable(R.drawable.balloons); 
mDrawable.setColorFilter(new PorterDuffColorFilter(0xffff00,PorterDuff.Mode.MULTIPLY));
myButton.setResource(mDrawable);
Papst answered 22/10, 2016 at 5:20 Comment(0)
H
0

You could construct the shapes from code, depending on the color you need to use, create a StateListDrawable from those and set it as your buttons background.

Heth answered 21/10, 2016 at 19:56 Comment(1)
I solved my own question, but if you explain your answer and give an example I'll give you a +1Papst

© 2022 - 2024 — McMap. All rights reserved.