В чем разница между выбранными, проверенными и активированными в Android состояниями?

Я хотел бы знать, что отличает эти состояния. Я не нашел ни одной веб-страницы, разъясняющей это.

Ответ 1

Разница между проверенными и активированными на самом деле довольно интересная. Даже документация Google является апологетической (добавление ниже):

... Например, в виде списка с одним или несколькими выделениями включены, в текущем наборе выбора активируются представления. (Um, да, мы очень сожалеем о терминологии здесь.) Активированный состояние распространяется до детей вида, на который оно установлено.

Итак, вот в чем разница:

  • Активированный был введен в Honeycomb, поэтому вы не можете использовать его до этого
  • Активированный теперь является свойством каждого представления. Он имеет методы setActivated() и isActivated()
  • Активированный распространяется на дочерние элементы представления, на котором он установлен
  • Проверено вращение вокруг представления, реализующего интерфейс Checkable. Методы setChecked(), isChecked(), toggle()
  • ListView (после Honeycomb) вызывает setChecked() ИЛИ setActivated() в зависимости от версии Android, как показано ниже (взято из исходного кода Android):

    if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
        if (child instanceof Checkable) {
            ((Checkable) child).setChecked(mCheckStates.get(position));
        } else if (getContext().getApplicationInfo().targetSdkVersion
                >= android.os.Build.VERSION_CODES.HONEYCOMB) {
            child.setActivated(mCheckStates.get(position));
        }
    }
    

    Обратите внимание на переменную mCheckStates. Он отслеживает, какие позиции в вашем списке проверены/активированы. Они доступны через, например, getCheckedItemPositions(). Также обратите внимание, что вызов ListView.setItemChecked() вызывает вышеупомянутое. Другими словами, его можно в равной степени называть setItemActivated().

  • До Honeycomb нам пришлось реализовать обходные пути, чтобы отразить state_checked в наших элементах списка. Это связано с тем, что ListView вызывает setChecked() ТОЛЬКО на самом верхнем представлении в макете (а макеты не реализуются с возможностью проверки)... и он не распространяется без помощи. Эти обходные пути имели следующую форму: Расширьте корневой макет для реализации Checkable. В своем конструкторе рекурсивно найдите всех детей, которые реализуют Checkable. Когда вызываются setChecked() и т.д., Передайте вызов этим представлениям. Если эти представления реализуют ярлыки списка состояний (например, CheckBox) с другим drawable для state_checked, тогда проверенное состояние отражается в пользовательском интерфейсе.

  • Чтобы сделать приятный фон в элементе списка после того, как Honeycomb вам понадобится, вы получите список состояний с возможностью рисования для состояния state_activated, как это (и, конечно, используйте setItemChecked()):

    <item android:state_pressed="true"
        android:drawable="@drawable/list_item_bg_pressed"/>
    <item android:state_activated="true"
        android:drawable="@drawable/list_item_bg_activated"/>
    <item android:drawable="@drawable/list_item_bg_normal"/>
    

  • Чтобы сделать хороший фон для элемента списка до HoneyComb, вы бы сделали что-то вроде выше для state_checked, и вам также нужно расширить свой верхний вид для реализации интерфейса Checkable. В этом случае вам нужно сообщить Android, является ли выполняемое вами состояние истинным или ложным, реализуя onCreateDrawableState() и вызывая refreshDrawableState() всякий раз, когда изменяется состояние.

    <item android:state_pressed="true"
        android:drawable="@drawable/list_item_bg_pressed"/>
    <item android:state_checked="true"
        android:drawable="@drawable/list_item_bg_checked"/>
    <item android:drawable="@drawable/list_item_bg_normal"/>
    

... и код для реализации Checkable в сочетании с state_checked в RelativeLayout может быть:

public class RelativeLayoutCheckable extends RelativeLayout implements Checkable {

    public RelativeLayoutCheckable(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public RelativeLayoutCheckable(Context context) {
        super(context);
    }

    private boolean mChecked = false;

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
    }
    @Override
    public boolean isChecked() {
        return mChecked;
    }

    @Override
    public void setChecked(boolean checked) {
        mChecked = checked;
        refreshDrawableState();
    }

    private static final int[] mCheckedStateSet = {
        android.R.attr.state_checked,
    };

    @Override
    protected int[] onCreateDrawableState(int extraSpace) {
        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
        if (isChecked()) {
            mergeDrawableStates(drawableState, mCheckedStateSet);
        }
        return drawableState;
    }    

    @Override
    public void toggle() {
        setChecked(!mChecked);
    }
}

Благодаря следующему:

http://sriramramani.wordpress.com/2012/11/17/custom-states/

Stackoverflow: Как добавить пользовательское состояние кнопки

Stackoverflow: Custom Checkable View, который отвечает Selector

http://www.charlesharley.com/2012/programming/custom-drawable-states-in-android/

http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList

http://blog.marvinlabs.com/2010/10/29/custom-listview-ability-check-items/

Ответ 2

В соответствии с doc:

  • android: state_selected Логическое. "true" , если этот элемент должен использоваться, когда объект является текущим выбором пользователя при навигации с контролем направления (например, при навигации по списку с d-pad); "false" , если этот элемент должен использоваться, когда объект не выбран. Выбранное состояние используется, когда фокус (android: state_focused) недостаточно (например, когда вид списка фокус и элемент внутри него выбирается с помощью d-pad).

  • android: state_checked Логическое. "true" , если этот элемент должен использоваться, когда объект проверен; "false" , если он должен использоваться, когда объект не проверен.

  • android: state_activated Логическое. "true" , если этот элемент должен использоваться, когда объект активирован как постоянный выбор (такой как "выделить" ранее выбранный элемент списка в постоянном навигационное представление); "false" , если он должен использоваться, когда объект не активируется. Представлен в уровне API 11.

Я думаю, что документ довольно ясен, так что проблема?

Ответ 3

Вот еще одно решение этой проблемы: https://github.com/jiahaoliuliu/CustomizedListRow/blob/master/src/com/jiahaoliuliu/android/customizedlistview/MainActivity.java

Я переопределил метод setOnItemClickListener и проверил разные случаи в коде. Но окончательно решение Марвина намного лучше.

listView.setOnItemClickListener(new OnItemClickListener() {

@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position,
        long id) {
    CheckedTextView checkedTextView =
            (CheckedTextView)view.findViewById(R.id.checkedTextView);
    // Save the actual selected row data
    boolean checked = checkedTextView.isChecked();
    int choiceMode = listView.getChoiceMode();
    switch (choiceMode) {
    // Not choosing anything
    case (ListView.CHOICE_MODE_NONE):
        // Clear all selected data
        clearSelection();
        //printCheckedElements();
        break;
    // Single choice
    case (ListView.CHOICE_MODE_SINGLE):
        // Clear all the selected data
        // Revert the actual row data
        clearSelection();
        toggle(checked, checkedTextView, position);
        //printCheckedElements();
        break;
    // Multiple choice
    case (ListView.CHOICE_MODE_MULTIPLE):
    case (ListView.CHOICE_MODE_MULTIPLE_MODAL):
        // Revert the actual selected row data
        toggle(checked, checkedTextView, position);
        //printCheckedElements();
        break;
    }
    }
});