Search code examples
androidxmlandroid-custom-viewandroid-drawableandroid-launcher

How to customize this drawable with parameters in Android?


This is the xml of "mydrawable" which I'm using as background for buttons

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="false" android:state_pressed="false" >
       <shape xmlns:android="http://schemas.android.com/apk/res/android"
            android:shape="rectangle">
            <gradient
                android:angle="-45"
                android:endColor="@color/colorPrimary700"
                android:startColor="@color/colorPrimary600"
                android:type="linear" />
            <corners android:radius="@dimen/ic_button_corner"></corners>
        </shape>
</item>
<item android:state_focused="false" android:state_pressed="true" >
        <shape xmlns:android="http://schemas.android.com/apk/res/android"
            android:shape="rectangle">
            <gradient
                android:angle="-45"
                android:endColor="@color/colorPrimary800"
                android:startColor="@color/colorPrimary700"
                android:type="linear" />
            <corners android:radius="@dimen/ic_button_corner"></corners>
        </shape>
</item>
</selector>

This is a use case

<Button
            android:id="@+id/login_button"
            style="?android:textAppearanceSmall"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/mydrawable"
            android:text="@string/log_in"/>

How to port this static drawable into a custom view with configurable parameters like the colors used in the gradients for each item and the size corner radius?

For example via Java

MyDrawable myDrawable=new MyDrawable();
myDrawable.setGradientColors(color1, color2);
myDrawable.setCornerRadius(size);
button.setBackground(Drawable);

Is it also possible via custom Button (MyButton, instead of MyDrawable)?

 <MyButton 
      parameter_gradientcolor1:@color/color1
      parameter_gradientcolor2:@color/color2
      ... />

EDIT

This is not working, neither reactions to click event nor correct gradient

public class SelectorButton extends AppCompatButton {

StateListDrawable mStateListDrawable;

public SelectorButton(Context context, AttributeSet attrs) {
    super(context, attrs);
    float cornerRadius = attrs.getAttributeFloatValue("app", "cornerRadius", 0);
    int normalStartColor = attrs.getAttributeIntValue("app", "normalStartColor", R.color.mds_grey_400);
    int normalEndColor = attrs.getAttributeIntValue("app", "normalEndColor", R.color.mds_grey_500);
    int pressedStartColor = attrs.getAttributeIntValue("app", "pressedStartColor", R.color.mds_grey_400);
    int pressedEndColor = attrs.getAttributeIntValue("app", "pressedEndColor", R.color.mds_grey_500);

    GradientDrawable normalDrawable = new GradientDrawable(
            GradientDrawable.Orientation.TOP_BOTTOM,
            new int[]{normalStartColor, normalEndColor});
    normalDrawable.setCornerRadius(cornerRadius);
    GradientDrawable pressedDrawable = new GradientDrawable(
            GradientDrawable.Orientation.TOP_BOTTOM,
            new int[]{pressedStartColor, pressedEndColor});
    pressedDrawable.setCornerRadius(cornerRadius);

    mStateListDrawable = new StateListDrawable();
    mStateListDrawable.addState(new int[]{-android.R.attr.state_pressed, -android.R.attr.state_focused},
            normalDrawable);
    mStateListDrawable.addState(new int[]{android.R.attr.state_pressed, -android.R.attr.state_focused},
            pressedDrawable);
    setBackground(mStateListDrawable);
}
}

This is in the layout

 <com.utils.views.SelectorButton
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Login"
    android:clickable="true"
    app:normalEndColor="@color/mds_blue_400"
    app:normalStartColor="@color/mds_red_500"
    app:pressedEndColor="@color/mds_amber_500"
    app:pressedStartColor="@color/mds_green_300" />

Solution

  • Yes, you can do this via custom button. Here is a code snippet.

    public class SelectorButton extends AppCompatButton {
        StateListDrawable mStateListDrawable;
    
        public SelectorButton(Context context, AttributeSet attrs) {
            super(context, attrs);
            mStateListDrawable = new StateListDrawable();
            GradientDrawable normalDrawable = new GradientDrawable(yourColor);
            normalDrawable.setCornerRadius(yourRadius);
            mStateListDrawable.addState(
                    new int[]{-android.R.attr.state_pressed, -android.R.attr.state_enabled}, );
            setBackground(mStateListDrawable);
        }
    
    }
    

    In order to set style via XML, you can define custom style such as colors or corner radius in attrs.xml.If you have any question, feel free to ask.

    EDIT

    Now I will show you how to declare custom style in XMLand use them. For example, I want to set normal and pressed state gradient color.

    In yourProject/app/src/main/res/values dir, create a new file called attrs.xml.

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="SelectorButton">
            <attr name="normalStartColor" format="color"/>
            <attr name="normalEndColor" format="color"/>
    
            <attr name="pressedStartColor" format="color"/>
            <attr name="pressedEndColor" format="color"/>
        </declare-styleable>
    </resources>
    

    As you see, I define four attributes.Now you can set these attributes via xml.

    <SelectorButton
        app:normalStartColor=""
        app:normalEndColor=""
        app:pressedStartColor=""
        app:pressedEndColor=""
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/> 
    

    EDIT: obtain values from xml

    Sorry for my mistakes. You can obtain these values like this.

        final TypedArray a = context.obtainStyledAttributes(
                attrs, R.styleable.SelectorButton, 0, 0);
        int normalStartColor = a.getColor(R.styleable.SelectorButton_normalStartColor, 0);
        a.recycle();
    

    And there is a pressed state. You can do like this.

        mStateListDrawable.addState(new int[]{android.R.attr.state_pressed, -android.R.attr.state_enabled}, pressedDrawable);