State_checked не включает и отключает просмотр изображений

Предварительный просмотр Android Studio 2.0

Здравствуйте,

У меня есть этот селектор, который подключен к imageview. Я хочу включить и выключить imageview. Таким образом, отобразится зеленый цвет и на дисплее будет отображаться красный цвет.

Однако, когда я нажимаю кнопку 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>

Большое спасибо за любые предложения,

Ответы

Ответ 1

Однако, когда я нажимаю изображение, ничего не происходит.

Итак, как сказал @Zielony, причина проста: ImageView не поддерживается проверенные состояния.

Каждый класс, расширенный из View, поддерживает разные состояния: нажатие, выделение, сфокусированное, проверяемое (обратите внимание, что не проверено состояние) и т.д. Но проверено - это особое состояние. И лишь немногие View поддерживают его: ToggleButton, Switch, RadioButton, CheckBox, CheckedTextView. Они реализовали интерфейс Checkable.

У вас есть варианты решения вашего дела, но это зависит от того, что именно вам нужно:

  • Если вам действительно нужна эта простая вещь

    Таким образом, выкл. будет отображать зеленый цвет и на дисплее будет отображаться красный цвет.

    вы можете использовать CheckBox или CheckedTextView, например. Просто создайте селектор:

    <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, но будьте осторожны, потому что выбранное свойство переходного процесса)

    <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());
        }
    });
    
  • Напишите свой собственный проверяемый класс. Вы можете видеть от других людей, как это сделать:

    • Официальная реализация 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();
              }
          }
      }
      
    • Другая реализация в MultiChoiceAdapter

    • Реализация с OnCheckedChangeListener и сохраненным состоянием, например 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();
          }
      }
      

Эти варианты, которые приходят на ум во-первых и имеют хорошую реализацию. Но вы также можете придумать свои собственные версии или использовать простые переменные для сохранения состояния и переключения вручную, как сказал Чираг-Савсани, но в этом случае вам придется отказаться от использования selector s.

Ответ 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) Использование CheckBox

Используйте CheckBox с свойством android: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" />

Измените имя на зеленый и красный с помощью вашего имени.

Ответ 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

Подумайте о том, чтобы переключить ваш образ на кнопку, поскольку state_checked не влияет на изображение. Затем установите фон кнопки на свой selector_xml

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

Ответ 6

Попробуйте этот

< < < < < < Первый путь → → →

1. Создайте color.xml в папке "values" в папке "res", если она уже создана, создайте ее с каким-то другим именем: 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. Теперь установите свойство "android: background" вашего ImageView примерно таким же, как и для параметра 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"
    />

< < < < < < < Второй путь → → → >

Сделать файл в папке с возможностью переноса 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>

Теперь установите свойство "android: background" вашего ImageView, что-то вроде этого также установите 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"
    />