Я хотел бы знать, что отличает эти состояния. Я не нашел ни одной веб-страницы, разъясняющей это.
В чем разница между выбранными, проверенными и активированными в 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;
}
}
});