【问题标题】:state_checked doesn't toggle imageview on and offstate_checked 不会打开和关闭 imageview
【发布时间】:2016-02-29 18:06:39
【问题描述】:

Android Studio 2.0 预览

你好,

我有这个连接到imageview 的选择器。我想打开和关闭imageview。所以 off 会显示绿色,on 会显示红色。

但是,当我单击 imageview 时,什么也没有发生。我尝试了 state_pressed 和 state_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>

非常感谢您的任何建议,

【问题讨论】:

  • 那么...既然 ImageView 有 checked 状态?
  • 我认为这就是选择器的用途。第一次检查 imageview 时,它将显示为红色以指示打开。再次单击时,它将变为绿色以指示关闭。
  • 那么,ImageView 不是您想要使用的 View。请改用CheckBox。您可能想要自定义其 button 可绘制对象。可能重复:stackoverflow.com/questions/3192173/…
  • 将其更改为 ToggleButton。参考这个:stackoverflow.com/questions/2716686/…
  • Android Studio 错误地将android:checked 自动完成功能赋予ImageView。我也浪费了时间。

标签: android


【解决方案1】:

但是,当我单击图像视图时,什么也没有发生。

所以,正如 @Zielony 所说,原因很简单:ImageView 不支持 checked 状态。

View 扩展的每个类都支持不同的状态:pressedselectedfocusedcheckable(注意不是 checked 状态)等。但是 checked 是特殊状态。只有少数Views 支持它:ToggleButtonSwitchRadioButtonCheckBoxCheckedTextView。他们实现了Checkable 接口。

你有不同的方法来解决你的问题,但这取决于你到底需要什么:

  1. 如果你真的想要这个简单的东西

    所以关闭将显示绿色,打开将显示红色。

    例如,您可以使用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>"/>
    
  2. 使用其他状态。您可以使用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());
        }
    });
    
  3. 编写您自己的可检查类。你可以从其他人那里看到如何做到这一点:

    1. 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();
              }
          }
      }
      
    2. Other implementation in MultiChoiceAdapter

    3. Implementation with OnCheckedChangeListener and saved state, like CheckBox class 这也是我见过的最好的实现

      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 所说的那样手动切换,但在这种情况下,您将不得不放弃使用 selector秒。

【讨论】:

  • 第三个选项绝对是要走的路
  • 选项 2:从 state_checked 转换为 state_activated 并且更适合我的用例。谢谢!
【解决方案2】:

原因很简单——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

【讨论】:

    【解决方案3】:

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

    1) 使用复选框

    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>
    

    将 red_color 和 green_color 替换为您的可绘制名称。

    2) 使用ImageView

    全局声明此变量

    boolean switchStatus = false;
    

    找到您的 ImageView 并在下方添加 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 在布局文件中。

    <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" 解决了我的问题
    【解决方案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
            }
    
        });
    

    【讨论】:

      【解决方案5】:

      考虑将您的 imageView 切换为 Button,因为 state_checked 不会影响 imageView。 然后将按钮的背景设置为您的 selector_xml

      <Button>
      ...
      android:background="@drawable/your_selector_xml"
      </Button>
      

      【讨论】:

        【解决方案6】:

        试试这个

        >>>>>

        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"
            />
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-11-14
          • 1970-01-01
          相关资源
          最近更新 更多