Android 中选中、选中和激活的状态有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11504860/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the difference between the states selected, checked and activated in Android?
提问by Louis
I'd like to know what differs those states. I didn't find any webpage clarifying this.
我想知道这些州有什么不同。我没有找到任何网页来澄清这一点。
回答by Martin Harvey
The difference between Checked and Activated is actually quite interesting. Even the Google documentation is apologetic (emphasis below added):
Checked 和 Activated 之间的区别实际上非常有趣。甚至 Google 文档也很抱歉(强调在下面添加):
... 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.)The activated state is propagated down to children of the view it is set on.
... 例如,在启用单选或多选的列表视图中,当前选择集中的视图被激活。(嗯,是的,我们对这里的术语深表歉意。)激活状态向下传播到它所设置的视图的子级。
So here is the difference:
所以这是区别:
- Activated was introduced in Honeycomb so you can't use it before that
- Activated is now a property of every View. It has methods setActivated() and isActivated()
- Activated propagates to children of the View on which it is set
- Checked revolves around a View implementing the Checkable interface. Methods setChecked(), isChecked(), toggle()
ListView (after Honeycomb) calls setChecked() OR setActivated() depending on Android version as below (taken from Android source code):
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)); } }
Note the mCheckStates variable. It keeps track of which positions in your list are checked / activated. These are accessible via, for example, getCheckedItemPositions(). Note also that a call to ListView.setItemChecked() invokes the above. In other words, it could equally be called setItemActivated().
Prior to Honeycomb we had to implement workarounds to reflect state_checked in our list items. This is because ListView calls setChecked() ONLY on the topmost View in the layout (and layouts do not implement checkable) ... and it does NOT propagate without help. These workarounds were of the following form: Extend the root layout to implement Checkable. In its constructor, recursively find all the children that implement Checkable. When setChecked() etc... are called, pass the call on to those Views. If those views implement state list drawables (eg a CheckBox) with a different drawable for state_checked then the checked state is reflected in the UI.
To do a nice background to a list item after Honeycomb all you need do is have a state list drawable with a drawable for the state state_activated like this (and use setItemChecked() of course):
<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"/>
To do a nice background to a list item prior to HoneyComb you would do something like the above for state_checked and you ALSO need to extend your topmost view to implement the Checkable interface. Within that you then need to tell Android whether the state you are implementing is true or false by implementing onCreateDrawableState() and calling refreshDrawableState() whenever the state changes.
<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"/>
- Activated 是在 Honeycomb 中引入的,因此您不能在此之前使用它
- Activated 现在是每个视图的属性。它有方法 setActivated() 和 isActivated()
- Activated 传播到设置它的 View 的子级
- Checked 围绕实现 Checkable 接口的 View 展开。方法 setChecked()、isChecked()、toggle()
ListView(在 Honeycomb 之后)根据 Android 版本调用 setChecked() 或 setActivated() 如下(取自 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 仅在布局中的最顶层 View 上调用 setChecked() (并且布局不实现可检查)......并且它不会在没有帮助的情况下传播。这些变通方法采用以下形式: 扩展根布局以实现 Checkable。在其构造函数中,递归查找所有实现 Checkable 的子项。当 setChecked() 等...被调用时,将调用传递给这些视图。如果这些视图使用 state_checked 的不同可绘制对象实现状态列表可绘制对象(例如 CheckBox),则选中的状态将反映在 UI 中。
要在 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 接口。然后,您需要通过实现 onCreateDrawableState() 并在状态更改时调用 refreshDrawableState() 来告诉 Android 您正在实现的状态是真还是假。
<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"/>
... and the code to implement Checkable combined with state_checked in a RelativeLayout could be:
...并且在RelativeLayout中实现Checkable与state_checked结合的代码可能是:
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);
}
}
Thanks to the following:
感谢以下人员:
http://sriramramani.wordpress.com/2012/11/17/custom-states/
http://sriramramani.wordpress.com/2012/11/17/custom-states/
Stackoverflow: How to add a custom button state
Stackoverflow:如何添加自定义按钮状态
Stackoverflow: Custom Checkable View which responds to Selector
Stackoverflow:响应选择器的自定义可检查视图
http://www.charlesharley.com/2012/programming/custom-drawable-states-in-android/
http://www.charlesharley.com/2012/programming/custom-drawable-states-in-android/
http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList
http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList
http://blog.marvinlabs.com/2010/10/29/custom-listview-ability-check-items/
http://blog.marvinlabs.com/2010/10/29/custom-listview-ability-check-items/
回答by AMerle
According to the doc:
根据文档:
android:state_selectedBoolean. "
true
" if this item should be used when the object is the current user selection when navigating with a directional control (such as when navigating through a list with a d-pad); "false
" if this item should be used when the object is not selected. The selected state is used when focus (android:state_focused) is not sufficient (such as when list view has focus and an item within it is selected with a d-pad).android:state_checkedBoolean. "
true
" if this item should be used when the object is checked; "false
" if it should be used when the object is un-checked.android:state_activatedBoolean. "
true
" if this item should be used when the object is activated as the persistent selection (such as to "highlight" the previously selected list item in a persistent navigation view); "false
" if it should be used when the object is not activated. Introduced in API level 11.
android:state_selected布尔值。"
true
" 如果在使用方向控件导航时(例如在使用方向键导航列表时)对象是当前用户选择时应使用此项;"false
" 如果在未选择对象时应使用此项。当焦点 (android:state_focused) 不够用时(例如当列表视图具有焦点并且其中的一个项目被 d-pad 选中时)使用选中状态。android:state_checked布尔值。"
true
" 如果在检查对象时应使用此项;"false
" 如果在未选中对象时应该使用它。android:state_activated布尔值。"
true
" 如果在对象被激活为持久选择时应该使用此项(例如在持久导航视图中“突出显示”先前选择的列表项);"false
" 如果在对象未激活时应该使用它。在API 级别 11 中引入。
I think the doc is pretty clear, so what's the problem ?
我认为文档很清楚,所以有什么问题?
回答by jiahao
Here is other solution for this problem: https://github.com/jiahaoliuliu/CustomizedListRow/blob/master/src/com/jiahaoliuliu/android/customizedlistview/MainActivity.java
这是此问题的其他解决方案:https: //github.com/jiahaoliuliu/CustomizedListRow/blob/master/src/com/jiahaoliuliu/android/customizedlistview/MainActivity.java
I have overrided the method setOnItemClickListener and check differente cases in the code. But definitively the solution of Marvin is much better.
我已经覆盖了 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;
}
}
});