Skip to content

Instantly share code, notes, and snippets.

@AlexKorovyansky
Created March 9, 2015 12:52
Show Gist options
  • Save AlexKorovyansky/71f673b9840519152d1d to your computer and use it in GitHub Desktop.
Save AlexKorovyansky/71f673b9840519152d1d to your computer and use it in GitHub Desktop.
Implementation of checkable ImageButton, with behaviour similar to Checkbox and support of state_checked selectors. Based on http://kmansoft.com/2011/01/11/checkable-image-button/
public class CheckableImageButton extends ImageButton implements Checkable {
private boolean checked;
private boolean broadcasting;
private OnCheckedChangeListener onCheckedChangeListener;
private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };
public CheckableImageButton(Context context) {
this(context, null);
}
public CheckableImageButton(Context context, AttributeSet attrs) {
super(context, attrs);
int[] set = {
android.R.attr.checked, // idx 0
};
TypedArray a = context.obtainStyledAttributes(attrs, set);
boolean checked = a.getBoolean(0, false);
setChecked(checked);
a.recycle();
}
public void toggle() {
setChecked(!checked);
}
@Override
public boolean performClick() {
toggle();
return super.performClick();
}
public boolean isChecked() {
return checked;
}
/**
* <p>
* Changes the checked state of this button.
* </p>
*
* @param checked
* true to check the button, false to uncheck it
*/
public void setChecked(boolean checked) {
if (this.checked != checked) {
this.checked = checked;
refreshDrawableState();
// Avoid infinite recursions if setChecked() is called from a listener
if (broadcasting) {
return;
}
broadcasting = true;
if (onCheckedChangeListener != null) {
onCheckedChangeListener.onCheckedChanged(this, this.checked);
}
broadcasting = false;
}
}
/**
* Register a callback to be invoked when the checked state of this button changes.
*
* @param listener
* the callback to call on checked state change
*/
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
onCheckedChangeListener = listener;
}
/**
* Interface definition for a callback.
*/
public static interface OnCheckedChangeListener {
/**
* Called when the checked state of a button has changed.
*
* @param button
* The button view whose state has changed.
* @param isChecked
* The new checked state of button.
*/
void onCheckedChanged(CheckableImageButton button, boolean isChecked);
}
@Override
public int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
invalidate();
}
static class SavedState extends BaseSavedState {
boolean checked;
SavedState(Parcelable superState) {
super(superState);
}
private SavedState(Parcel in) {
super(in);
checked = (Boolean) in.readValue(null);
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeValue(checked);
}
public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.checked = isChecked();
return ss;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
setChecked(ss.checked);
requestLayout();
}
}
@aurozhkov
Copy link

Works like a charm!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment