style - raised button android




Standard Android Button with a different color (12)

I'd like to change the color of a standard Android button slightly in order to better match a client's branding.

The best way I've found to do this so far is to change the Button's drawable to the drawable located in res/drawable/red_button.xml:

<?xml version="1.0" encoding="utf-8"?>    
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@drawable/red_button_pressed" />
    <item android:state_focused="true" android:drawable="@drawable/red_button_focus" />
    <item android:drawable="@drawable/red_button_rest" />
</selector>

But doing that requires that I actually create three different drawables for each button I want to customize (one for the button at rest, one when focused, and one when pressed). That seems more complicated and non-DRY than I need.

All I really want to do is apply some sort of color transform to the button. Is there an easier way to go about changing a button's color than I'm doing?


The shortest solution which is working with any Android version:

<Button
     app:backgroundTint="@color/my_color"

Notes/Requirements:

  • Use the app: namespace and not the android: namespace!
  • appcompat version > 24.2.0

    dependencies { compile 'com.android.support:appcompat-v7:25.3.1' }

Explanation:


An easy way is to just define a custom Button class which accepts all the properties that you desire like radius, gradient, pressed color, normal color etc. and then just use that in your XML layouts instead of setting up the background using XML. A sample is here

This is extremely useful if you have a lot of buttons with same properties like radius, selected color etc. You can customize your inherited button to handle these additional properties.

Result (No Background selector was used).

Normal Button

Pressed Button


I am using this approach

style.xml

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:colorPrimaryDark">#413152</item>
    <item name="android:colorPrimary">#534364</item>
    <item name="android:colorAccent">#534364</item>
    <item name="android:buttonStyle">@style/MyButtonStyle</item>
</style>

<style name="MyButtonStyle" parent="Widget.AppCompat.Button.Colored">
    <item name="android:colorButtonNormal">#534364</item>
    <item name="android:textColor">#ffffff</item>
</style>

As you can see from above, I'm using a custom style for my button. The button color corresponds to the accent color. I find this a much better approach than setting android:background as I won't lose the ripple effect Google provides.


I discovered that this can all be done in one file fairly easily. Put something like the following code in a file named custom_button.xml and then set background="@drawable/custom_button" in your button view:

<?xml version="1.0" encoding="utf-8"?>
<selector
    xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_pressed="true" >
        <shape>
            <gradient
                android:startColor="@color/yellow1"
                android:endColor="@color/yellow2"
                android:angle="270" />
            <stroke
                android:width="3dp"
                android:color="@color/grey05" />
            <corners
                android:radius="3dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>
    </item>

    <item android:state_focused="true" >
        <shape>
            <gradient
                android:endColor="@color/orange4"
                android:startColor="@color/orange5"
                android:angle="270" />
            <stroke
                android:width="3dp"
                android:color="@color/grey05" />
            <corners
                android:radius="3dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>
    </item>

    <item>        
        <shape>
            <gradient
                android:endColor="@color/blue2"
                android:startColor="@color/blue25"
                android:angle="270" />
            <stroke
                android:width="3dp"
                android:color="@color/grey05" />
            <corners
                android:radius="3dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>
    </item>
</selector>

If you are making colour buttons with XML you can make the code a bit cleaner by specifying the focused and pressed state in a separate file and reuse them. My green button looks like this:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_focused="true" android:drawable="@drawable/button_focused"/>
    <item android:state_pressed="true" android:drawable="@drawable/button_pressed"/>

    <item>
        <shape>
            <gradient android:startColor="#ff00ff00" android:endColor="#bb00ff00" android:angle="270" />
            <stroke android:width="1dp" android:color="#bb00ff00" />
            <corners android:radius="3dp" />
            <padding android:left="10dp" android:top="10dp" android:right="10dp" android:bottom="10dp" />
        </shape>
    </item>

</selector>

In <Button> use android:background="#33b5e5". or better android:background="@color/navig_button"


The DroidUX component library has a ColorButton widget whose color can be changed easily, both via xml definition and programmatically at run time, so you can even let the user to set the button's color/theme if your app allows it.


The way I do a different styled button that works quite well is to subclass the Button object and apply a colour filter. This also handles enabled and disabled states by applying an alpha to the button.

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.LightingColorFilter;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.Button;

public class DimmableButton extends Button {

    public DimmableButton(Context context) {
        super(context);
    }

    public DimmableButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public DimmableButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @SuppressWarnings("deprecation")
    @Override
    public void setBackgroundDrawable(Drawable d) {
        // Replace the original background drawable (e.g. image) with a LayerDrawable that
        // contains the original drawable.
        DimmableButtonBackgroundDrawable layer = new DimmableButtonBackgroundDrawable(d);
        super.setBackgroundDrawable(layer);
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public void setBackground(Drawable d) {
        // Replace the original background drawable (e.g. image) with a LayerDrawable that
        // contains the original drawable.
        DimmableButtonBackgroundDrawable layer = new DimmableButtonBackgroundDrawable(d);
        super.setBackground(layer);
    }

    /**
     * The stateful LayerDrawable used by this button.
     */
    protected class DimmableButtonBackgroundDrawable extends LayerDrawable {

        // The color filter to apply when the button is pressed
        protected ColorFilter _pressedFilter = new LightingColorFilter(Color.LTGRAY, 1);
        // Alpha value when the button is disabled
        protected int _disabledAlpha = 100;
        // Alpha value when the button is enabled
        protected int _fullAlpha = 255;

        public DimmableButtonBackgroundDrawable(Drawable d) {
            super(new Drawable[] { d });
        }

        @Override
        protected boolean onStateChange(int[] states) {
            boolean enabled = false;
            boolean pressed = false;

            for (int state : states) {
                if (state == android.R.attr.state_enabled)
                    enabled = true;
                else if (state == android.R.attr.state_pressed)
                    pressed = true;
            }

            mutate();
            if (enabled && pressed) {
                setColorFilter(_pressedFilter);
            } else if (!enabled) {
                setColorFilter(null);
                setAlpha(_disabledAlpha);
            } else {
                setColorFilter(null);
                setAlpha(_fullAlpha);
            }

            invalidateSelf();

            return super.onStateChange(states);
        }

        @Override
        public boolean isStateful() {
            return true;
        }
    }

}

This is my solution which perfectly works starting from API 15. This solution keeps all default button click effects, like material RippleEffect. I have not tested it on lower APIs, but it should work.

All you need to do, is:

1) Create a style which changes only colorAccent:

<style name="Facebook.Button" parent="ThemeOverlay.AppCompat">
    <item name="colorAccent">@color/com_facebook_blue</item>
</style>

I recommend using ThemeOverlay.AppCompat or your main AppTheme as parent, to keep the rest of your styles.

2) Add these two lines to your button widget:

style="@style/Widget.AppCompat.Button.Colored"
android:theme="@style/Facebook.Button"

Sometimes your new colorAccent isn't showing in Android Studio Preview, but when you launch your app on the phone, the color will be changed.


Sample Button widget

<Button
    android:id="@+id/sign_in_with_facebook"
    style="@style/Widget.AppCompat.Button.Colored"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:text="@string/sign_in_facebook"
    android:textColor="@android:color/white"
    android:theme="@style/Facebook.Button" />


Use it in this way:

buttonOBJ.getBackground().setColorFilter(Color.parseColor("#YOUR_HEX_COLOR_CODE"), PorterDuff.Mode.MULTIPLY);

You can now also use appcompat-v7's AppCompatButton with the backgroundTint attribute:

<android.support.v7.widget.AppCompatButton
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:backgroundTint="#ffaa00"/>

You can set theme of your button to this

<style name="AppTheme.ButtonBlue" parent="Widget.AppCompat.Button.Colored">
 <item name="colorButtonNormal">@color/HEXColor</item>
 <item name="android:textColor">@color/HEXColor</item>
</style>




android-layout