Android Studio 2.0 preview
Hello,
I have this selector that is connected to an imageview
. I want to toggle the imageview
on and off. So off will display a green color and on will display a red color.
However, when I click the imageview
nothing happens. I have tried different combinations of state_pressed and state_checked. And now its getting too confusing. What am I missing here.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false"
android:drawable="@drawable/bottom_left_border"/>
<item android:state_checked="true"
android:drawable="@drawable/bottom_left_border_pressed">
</item>
</selector>
Many thanks for any suggestions,
However, when I click the imageview nothing happens.
So, as @Zielony said, the reason is simple: ImageView
not supported checked states.
Each class extended from View
supports different states: pressed, selected, focused, checkable (note that is not checked state) etc. But checked is special state. And only few View
s support it: ToggleButton
, Switch
, RadioButton
, CheckBox
, CheckedTextView
. They implemented Checkable
interface.
You have variants how to solve your case, but it depends what exactly you need:
If you really want this simple thing
So off will display a green color and on will display a red color.
you can use CheckBox
or CheckedTextView
for example. Just create selector:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="<red_color>" android:state_checked="true" />
<item android:drawable="<green_color>" />
</selector>
and use it
<CheckBox
android:layout_width="50dp"
android:layout_height="50dp"
android:text=""
android:button="@null"
android:clickable="true"
android:background="<your_selector>"/>
Use other state. You can use state_activated
(or state_selected
but, be careful, because selected is transient property)
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="<red_color>" android:state_activated="true" />
<item android:drawable="<green_color>" />
</selector>
and toggle this state by code
<your_image_view>.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
<your_image_view>.setActivated(!<your_image_view>.isActivated());
}
});
Write your own checkable class. You can see from other people how to do it:
Official android implementation from old Contacts application
public class CheckableImageView extends ImageView implements Checkable {
private boolean mChecked;
private static final int[] CHECKED_STATE_SET = {
android.R.attr.state_checked
};
public CheckableImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
}
public void toggle() {
setChecked(!mChecked);
}
public boolean isChecked() {
return mChecked;
}
public void setChecked(boolean checked) {
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
}
}
}
Other implementation in MultiChoiceAdapter
Implementation with OnCheckedChangeListener
and saved state, like CheckBox
class and also this is the best implementation I've ever seen
public class CheckableImageView extends ImageView implements Checkable {
private static final int[] checkedStateSet = { android.R.attr.state_checked };
private boolean mChecked = false;
private OnCheckedChangeListener mOnCheckedChangeListener;
private boolean mBroadcasting;
public CheckableImageView(Context context) {
super(context);
}
public CheckableImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CheckableImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean isChecked() {
return mChecked;
}
@Override
public boolean performClick() {
toggle();
return super.performClick();
}
@Override
public void toggle() {
setChecked(!mChecked);
}
@Override
public int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, checkedStateSet);
}
return drawableState;
}
@Override
public void setChecked(boolean checked) {
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
// Avoid infinite recursions if setChecked() is called from a listener
if (mBroadcasting) {
return;
}
mBroadcasting = true;
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onCheckedChanged(this, mChecked);
}
mBroadcasting = 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) {
mOnCheckedChangeListener = listener;
}
/**
* Interface definition for a callback to be invoked when the checked state
* of a compound button changed.
*/
public static interface OnCheckedChangeListener {
/**
* Called when the checked state of a compound button has changed.
*
* @param buttonView The compound button view whose state has changed.
* @param isChecked The new checked state of buttonView.
*/
void onCheckedChanged(CheckableImageView buttonView, boolean isChecked);
}
static class SavedState extends BaseSavedState {
boolean checked;
/**
* Constructor called from {@link CompoundButton#onSaveInstanceState()}
*/
SavedState(Parcelable superState) {
super(superState);
}
/**
* Constructor called from {@link #CREATOR}
*/
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);
}
@Override
public String toString() {
return "CheckableImageView.SavedState{" + Integer.toHexString(System.identityHashCode(this)) + " checked=" + checked + "}";
}
public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@Override
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();
}
}
This options that come to mind firstly and have a good implementation. But you can also come up with your own versions, or use simple variables to save state and toggle manualy like @Chirag-Savsani said, but in that case you would have to abandon to use of selector
s.
The reason is very simple - ImageView doesn't check for state_checked at all. Comment by @frank-n-stein is the closest to an answer for this question.
You have two options:
To add state_checked support you have to implement Checkable interface. Like this:
public class CheckableImageView extends ImageView implements Checkable {
private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
private boolean mChecked;
... constructors
@Override
public void setChecked(boolean checked) {
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
}
}
@Override
public boolean isChecked() {
return mChecked;
}
@Override
public void toggle() {
setChecked(!mChecked);
}
@Override
public boolean performClick() {
toggle();
return super.performClick();
}
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
}
@Override
protected Parcelable onSaveInstanceState() {
SavedState result = new SavedState(super.onSaveInstanceState());
result.checked = mChecked;
return result;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
setChecked(ss.checked);
}
protected static class SavedState extends BaseSavedState {
protected boolean checked;
protected SavedState(Parcelable superState) {
super(superState);
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(checked ? 1 : 0);
}
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];
}
};
private SavedState(Parcel in) {
super(in);
checked = in.readInt() == 1;
}
}
}
The code is from here: https://github.com/shomeser/AndroidLayoutSelector/blob/master/LayoutSelector/src/main/java/com/example/layoutselector/CheckableLinearLayout.java
Hello I also use this scenario in my current application.
1) Using CheckBox
Use CheckBox
with android:button="@null"
property,
This property will remove border of CheckBox
and display only your drawable images.
state_checked
property will work with CheckBox
<CheckBox
android:id="@+id/imgDisplayCheckimg"
android:layout_width="wrap_contenrt"
android:layout_height="wrap_contenrt"
android:background="@drawable/display_checkbox"
android:button="@null"
android:checked="false"
android:clickable="true" />
This is Drawable file display_checkbox.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- When selected, use red-->
<item android:drawable="@drawable/red_color" android:state_checked="true"/>
<!-- When not selected, use green-->
<item android:drawable="@drawable/green_color" android:state_checked="false"/>
</selector>
Replace red_color and green_color with your drawable name.
2) Using ImageView
Declare this variable Globally
boolean switchStatus = false;
Find your ImageView and add below Click Listener.
switchImageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(switchStatus == true) {
anonymousImage.setImageResource(R.drawable.red);
switchStatus = false;
} else {
anonymousImage.setImageResource(R.drawable.green);
switchStatus = true;
}
}
});
ImageView
in layout file.
<ImageView
android:id="@+id/switchImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/green" />
Change name at green and red with your drawable name.
You can try:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected ="false"
android:drawable="@drawable/bottom_left_border"/>
<item android:state_selected ="true"
android:drawable="@drawable/bottom_left_border_pressed">
</item>
</selector>
And java code:
imageview.setImageDrawable(getBaseContext().getResources().getDrawable(R.drawable....));
//set the click listener
imageview.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
v.setSelected(!v.isSelected());
//other code if need
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With