state_checked无法切换ImageView的开关

18

Android Studio 2.0预览版

Hello,

我有一个连接到imageview的选择器。我想要在开和关之间切换imageview。关闭时将显示绿色,打开时将显示红色。

然而,当我点击imageview时什么也没有发生。我尝试过不同的state_pressedstate_checked状态组合。现在变得太混乱了。我错过了什么。

<?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>

非常感谢您的任何建议,


3
自从什么时候 ImageView 有“checked”状态了? - Phantômaxx
我认为这就是选择器的作用。当imageview第一次被选中时,它将变成红色以表示开启。再次点击后,它将变成绿色以表示关闭。 - ant2009
1
嗯,那么 ImageView 不是你想要使用的 View。相反,使用 CheckBox。您可能需要自定义其 button drawable。可能是重复的问题:https://dev59.com/b3A75IYBdhLWcg3wo6le - Phantômaxx
将其更改为ToggleButton。请参考此链接:https://dev59.com/SXE85IYBdhLWcg3wkkU8 - androidEnthusiast
Android Studio错误地将android:checked自动完成为ImageView。我也浪费了时间。 - Youngjae
6个回答

17
然而,当我点击图像视图时没有任何反应。正如@Zielony所说,原因很简单:ImageView不支持checked状态。 每个继承自View的类都支持不同的状态:pressedselectedfocusedcheckable(请注意,这不是checked状态)等等。但是checked状态是特殊的状态。只有少数几个View支持它:ToggleButtonSwitchRadioButtonCheckBoxCheckedTextView。它们实现了Checkable接口。
您有几种解决方案可供选择,但具体取决于您需要什么:
1. 如果你真的只想要这个简单的东西

So off will display a green color and on will display a red color.

例如,您可以使用CheckBoxCheckedTextView。只需创建选择器即可:
<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>

并使用它

<CheckBox
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:text=""
    android:button="@null"
    android:clickable="true"
    android:background="<your_selector>"/>
使用其他状态。您可以使用state_activated(或state_selected,但要注意,因为selected是瞬态属性)。
<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>

并且可以通过代码切换这个状态

<your_image_view>.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        <your_image_view>.setActivated(!<your_image_view>.isActivated());
    }
});
  • 编写自己的可勾选类。您可以从其他人那里学习如何做到:

    1. 旧版联系人应用程序中官方Android实现

      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();
              }
          }
      }
      
    2. 在MultiChoiceAdapter中的其他实现

    3. 使用OnCheckedChangeListener和保存状态进行实现,类似于CheckBox类,这也是我见过最好的实现方式

    4. 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();
          }
      }
      
  • 这是我首先想到并且有良好实现的选项。 但是您也可以提出自己的版本,或者使用简单的变量保存状态并手动切换,如@Chirag-Savsani所说,但在这种情况下,您将不得不放弃使用选择器


    第三个选项绝对是最好的选择。 - Sree
    选项2:从state_checked转换为state_activated,并且对我的使用情况更有效。谢谢! - user1652110

    9

    原因很简单 - ImageView根本不检查state_checked状态。@frank-n-stein的评论是这个问题最接近答案的。

    您有两个选择:

    • 使用支持state_checked状态的视图(例如CheckBox)
    • 将state_checked添加到ImageView中

    要添加state_checked支持,您必须实现Checkable接口。像这样:

    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;
            }
        }
    }
    

    代码来自这里:https://github.com/shomeser/AndroidLayoutSelector/blob/master/LayoutSelector/src/main/java/com/example/layoutselector/CheckableLinearLayout.java。此代码与 Android 布局选择器有关。

    9

    你好,我也在我的当前应用程序中使用这个场景。

    1)使用CheckBox

    使用CheckBoxandroid:button="@null"属性, 此属性将删除CheckBox的边框,并仅显示您的可绘制图像。

    state_checked属性将与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" />
    

    这是一个可绘制文件,名为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>
    

    请使用你的Drawable名称替换red_color和green_color。

    2)使用ImageView

    全局声明这个变量

    boolean switchStatus = false;
    

    找到你的ImageView并添加以下点击监听器。
    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

    <ImageView
        android:id="@+id/switchImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/green" />
    

    使用您的可绘制名称更改绿色和红色的名称。


    通过 android:background="@drawable/display_checkbox" 和 android:button="@null" 解决了我的问题。 - Ahmad Shahwaiz

    4

    您可以尝试以下操作:

    <?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>
    

    以下是 Java 代码:

    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
            }
    
        });
    

    3
    考虑将您的imageView更换为Button,因为state_checked对imageView没有影响。然后将您的button的背景设置为selector_xml。
    <Button>
    ...
    android:background="@drawable/your_selector_xml"
    </Button>
    

    1

    试试这个

    <<<<<< 第一种方法 >>>>>>

    1. 如果还没有创建,请在“res”文件夹下的“values”文件夹中创建一个名为color.xml的文件;如果已经创建,请使用其他名称:color.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <drawable name="red">#FF0000</drawable>
        <drawable name="green">#00FF00</drawable>
        <drawable name="blue">#0000FF</drawable>    
    </resources>
    

    2.现在创建一个选择器,例如on_off_selector.xml:

    <?xml version="1.0" encoding="utf-8"?> 
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
         <item android:state_pressed="false" android:drawable="@drawable/red" />
         <item android:state_pressed="true" android:drawable="@drawable/green"/>   </selector>
    

    3. 现在设置你的ImageView的"android:background"属性,类似于下面这样,还需设置android:clcikable = "true":

    <ImageView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:clickable="true"
        android:id="@+id/imageView"
        android:background="@drawable/on_off_selector"
        />
    

    <<<<<<< 第二种方法 >>>>>>>

    在drawable文件夹中创建一个名为 on_off_selecor.xml 的文件。

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_pressed="false">
            <color android:color="#FF0000" />
        </item>
        <item android:state_pressed="true">
            <color android:color="#00FF00" />
        </item>
        <item>
            <color android:color="#FF0000" />
        </item>
    </selector>
    

    现在设置您的ImageView的"android:background"属性,例如这样,还要设置android:clcikable = "true":
    <ImageView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:clickable="true"
        android:id="@+id/imageView"
        android:background="@drawable/on_off_selector"
        />
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接