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

114

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

Луис
источник
4
Состояния представления (например, элемента ListView) developer.android.com/guide/topics/resources/…
Луи,
stackoverflow.com/questions/13634259/… - похожий вопрос, который помог мне лучше понять это. Проверьте это, если хотите узнать больше.
Acsor

Ответы:

182

На самом деле разница между Проверено и Активировано довольно интересно. Даже документация Google извиняется (выделение добавлено ниже):

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

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

  1. Activated был представлен в Honeycomb, поэтому вы не можете использовать его до этого
  2. Активировано теперь является свойством каждого просмотра. Он имеет методы setActivated () и isActivated ().
  3. Activated распространяется на дочерние элементы View, для которого он установлен.
  4. Checked вращается вокруг View, реализующего интерфейс Checkable. Методы setChecked (), isChecked (), toggle ()
  5. 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 ().

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

  7. Чтобы сделать красивый фон для элемента списка после 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"/>
    

  8. Чтобы сделать красивый фон для элемента списка до 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: настраиваемый проверяемый вид, который реагирует на селектор

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/

Мартин Харви
источник
4
этот ответ бесценен. Хотел бы я прочитать его, прежде чем пытаться понять, как реализовать макет Checkable и т.д. Большое спасибо.
Блейк Мамфорд
12
отличный ответ, но не касается «избранных» пунктов. Я нашел ответ в предложениях ПРАВО ПЕРЕД тем, которое вы процитировали: Selection is a transient property, representing the view (hierarchy) the user is currently interacting with. Activation is a longer-term state that the user can move views in and out of. For example, in a list view with single or multiple selection enabled, the views in the current selection set are activated. (Um, yeah, we are deeply sorry about the terminology here.) source
woojoo666
мой пользовательский цвет фона отображается только за выбранными / сфокусированными элементами, а не за отмеченными элементами, при использовании метода post-Honeycomb, который вы опубликовали выше: вызов, setItemChecked()а затем использование селектора со свойствомandroid:state_activated="true"
woojoo666
1
Большое вам спасибо, я потратил 3 дня, пытаясь понять это, пока наконец не решил спросить себя: «В чем разница между отмеченным, выбранным и активированным», отстой, что работа с чем-то таким простым, как меню, должна быть такой сложной, чрезмерной гениями Google, это почти похоже на препятствие, созданное этой компанией специально, чтобы замедлить других.
Губатрон
20

Согласно документу :

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

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

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

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

AMerle
источник
5
Не могли бы вы подробнее рассказать об android: state_selected. При каких обстоятельствах он установлен на true?
Андерсон
@Anderson это будет зависеть от ViewGroup, которую вы используете - ListView, RecyclerView (возможно, его LayoutManager), GridView может иметь разные реализации: ListView вызывает setFocused, где GridView вызывает setSelected, например. Это может быть просто случай проверки вашего приложения на разных версиях платформы.
атаулм
1
@Anderson: Если у вас есть список, и у пользователя есть клавиши со стрелками, одна из них «выбрана», и когда они стрелки вверх / вниз, выбор перемещается вверх / вниз. Когда они нажимают кнопку «активировать», он «активирует» элемент управления, воспринимая его выбор как отдаленно похожий на наведение курсора, а проверку / активацию как на отдаленно похожий на щелчок.
Mooing Duck
Мне было интересно, я собираюсь использовать активированный для выделения одного элемента в представлении списка, но устанавливает ли он для активации для других элементов списка значение false ... если не сделать что-либо из этого, сделайте это, поэтому мне не нужно искать другой активированный дочерний элемент и установите для активации значение false?
Lion789
0

Вот другое решение этой проблемы: 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;
    }
    }
});
Jiahao
источник