I have been working on my game and I have tons of image buttons I would like to have some advice from you guys is there an alternative way to simplices button states since I would like to have that functionality where the appearance of buttons changes when user press it
<?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/setting1"
/>
<item
android:drawable="@drawable/setting"
/>
</selector>
just like this right now I have a lot of this in my project and hope there would be an alternative way my polluted drawable folder
CodePudding user response:
Instead of having a lot of drawable xml selectors you can create one custom ImageButton and create programmatically all the button states using the StateListDrawable. Example will be like the below:
First create your CustomButton which extends from AppCompatImageButton
like the below:
public class CustomButton extends androidx.appcompat.widget.AppCompatImageButton {
public CustomButton(@NonNull Context context) {
super(context);
init(context, null, 0);
}
public CustomButton(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public CustomButton(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
private void init(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr){
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomButton, defStyleAttr, 0);
try {
int defaultDrawableResId = typedArray.getResourceId(R.styleable.CustomButton_drawable_default, -1);
int pressedDrawableResId = typedArray.getResourceId(R.styleable.CustomButton_drawable_pressed, -1);
StateListDrawable stateListDrawable = new StateListDrawable();
if(pressedDrawableResId!=-1) {
stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, ContextCompat.getDrawable(context, pressedDrawableResId));
}
if(defaultDrawableResId!=-1) {
stateListDrawable.addState(new int[]{}, ContextCompat.getDrawable(context, defaultDrawableResId));
}
setBackground(stateListDrawable);
}
catch (Exception e){
Log.e("CustomButton", e.getMessage());
}
finally {
typedArray.recycle();
}
}
}
Declare the CustomButton styleable under the res>values>attrs.xml
like the below:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomButton">
<attr name="drawable_default" format="reference" />
<attr name="drawable_pressed" format="reference" />
</declare-styleable>
</resources>
And then use this CustomButton in every layout needed by adding only the two states drawables (pressed|default) app:drawable_default
and app:drawable_pressed
like the below example layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.my.packagename.CustomButton
android:layout_width="80dp"
android:layout_height="80dp"
app:drawable_default="@drawable/settings"
app:drawable_pressed="@drawable/settings1"/>
</RelativeLayout>
This will eliminate all your xml drawable selectors and gives you also the ability to reuse any UI and any logic used inside the CustomButton.