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

自古美人都是妖i 提交于 2019-11-27 07:33:17

问题


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?


回答1:


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.




回答2:


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



回答3:


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.



来源:https://stackoverflow.com/questions/40183852/defined-custom-shape-for-button-in-xml-now-i-want-to-change-the-color-dynamical

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!