How to Add a Custom Button State

How to add a custom button state

The solution indicated by @(Ted Hopp) works, but needs a little correction: in the selector, the item states need an "app:" prefix, otherwise the inflater won't recognise the namespace correctly, and will fail silently; at least this is what happens to me.

Allow me to report here the whole solution, with some more details:

First, create file "res/values/attrs.xml":

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="food">
<attr name="state_fried" format="boolean" />
<attr name="state_baked" format="boolean" />
</declare-styleable>
</resources>

Then define your custom class. For instance, it may be a class "FoodButton", derived from class "Button". You will have to implement a constructor; implement this one, which seems to be the one used by the inflater:

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

On top of the derived class:

private static final int[] STATE_FRIED = {R.attr.state_fried};
private static final int[] STATE_BAKED = {R.attr.state_baked};

Also, your state variables:

private boolean mIsFried = false;
private boolean mIsBaked = false;

And a couple of setters:

public void setFried(boolean isFried) {mIsFried = isFried;}
public void setBaked(boolean isBaked) {mIsBaked = isBaked;}

Then override function "onCreateDrawableState":

@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
if (mIsFried) {
mergeDrawableStates(drawableState, STATE_FRIED);
}
if (mIsBaked) {
mergeDrawableStates(drawableState, STATE_BAKED);
}
return drawableState;
}

Finally, the most delicate piece of this puzzle; the selector defining the StateListDrawable that you will use as a background for your widget. This is file "res/drawable/food_button.xml":

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.mydomain.mypackage">
<item
app:state_baked="true"
app:state_fried="false"
android:drawable="@drawable/item_baked" />
<item
app:state_baked="false"
app:state_fried="true"
android:drawable="@drawable/item_fried" />
<item
app:state_baked="true"
app:state_fried="true"
android:drawable="@drawable/item_overcooked" />
<item
app:state_baked="false"
app:state_fried="false"
android:drawable="@drawable/item_raw" />
</selector>

Notice the "app:" prefix, whereas with standard android states you would have used prefix "android:". The XML namespace is crucial for a correct interpretation by the inflater and depends on the type of project in which you are adding attributes. If it is an application, replace com.mydomain.mypackage with the actual package name of your application (application name excluded). If it is a library you must use "http://schemas.android.com/apk/res-auto" (and be using Tools R17 or later) or you will get runtime errors.

A couple of notes:

  • It seems you don't need to call the "refreshDrawableState" function, at least the solution works well as is, in my case

  • In order to use your custom class in a layout xml file, you will have to specify the fully qualified name (e.g. com.mydomain.mypackage.FoodButton)

  • You can as weel mix-up standard states (e.g. android:pressed, android:enabled, android:selected) with custom states, in order to represent more complicated state combinations

Custom button with custom state

In your CustomButton, class override onCreateDrawableState, to merge your custom state:

private static final int[] STATE_AVAILABLE = { R.attr.state_available };

@Override
public int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (available) {
mergeDrawableStates(drawableState, STATE_AVAILABLE);
}
return drawableState;
}

mergeDrawableStates will merge your custom state, STATE_AVAILABLE into the base states

Android Custom Button Pressed State

Switch the order of the items (so pressed first, then neutral). Pressed or not, the top item is always true.

How do I set clicked state for my custom button?

You will save this as an xml file in res/drawable folder. If this folder does not exist, create it. In the example, the file name that I use is selector_drawable_name.xml

Following this, whenever you use a Button, and want it to have the click effect, set its background to this drawable:

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1"
android:background="@drawable/selector_drawable_name" />

Result: When the button's state changes to state_pressed, the background selected will be @drawable/boutonnpousse. Default (in every other state) will be @drawable/boutonn.

Change state from custom button in React Native

You are using functional component so you don't need this.

   <AppButton title ="OUI" onPress={()=>setIsWorkoutDone(true)}/>
<AppButton title ="NON" onPress={()=>setIsWorkoutDone(false)}/>

How to set custom highlighted state of SwiftUI Button


Updated for SwiftUI beta 5

SwiftUI does actually expose an API for this: ButtonStyle.

struct MyButtonStyle: ButtonStyle {

func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.padding()
.foregroundColor(.white)
.background(configuration.isPressed ? Color.red : Color.blue)
.cornerRadius(8.0)
}

}


// To use it
Button(action: {}) {
Text("Hello World")
}
.buttonStyle(MyButtonStyle())

How to set custom button state background color?

The xml you posted is suitable for a color state list, not a state list drawable. Try this instead:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:state_pressed="false" >
<shape><solid android:color="@color/green"/></shape>
</item>
. . .
</selector>

Alternatively, put your existing file into res/color and use it as you would any other color. However, I don't remember if you can use a color state list directly as a background for a view.



Related Topics



Leave a reply



Submit