我想知道这些州有什么不同。我没有找到任何网页来澄清这一点。
3 回答
Checked 和 Activated 的区别其实很有趣。甚至谷歌文档也很抱歉(在下面添加了重点):
... 例如,在启用单选或多选的列表视图中,当前选择集中的视图被激活。(嗯,是的,我们对这里的术语深表歉意。)激活状态被传播到它所设置的视图的子视图。
所以这里有区别:
- 激活是在 Honeycomb 中引入的,所以在此之前你不能使用它
- 已激活现在是每个视图的属性。它有方法 setActivated() 和 isActivated()
- 已激活传播到设置它的视图的子级
- 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)); } }
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"/>
... and the code to implement Checkable combined with state_checked in a RelativeLayout could be:
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/
Stackoverflow: How to add a custom button state
Stackoverflow: Custom Checkable View which responds to 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/
根据文档:
android:state_selected 布尔值。"
true
" 如果在使用方向控件导航时(例如在使用 d-pad 导航列表时)对象是当前用户选择时应使用此项目;"false
" 如果在未选择对象时应使用此项。当焦点 (android:state_focused) 不够时(例如当列表视图具有焦点并且使用 d-pad 选择其中的项目时)使用选定状态。android:state_checked 布尔值。"
true
" 如果在检查对象时应该使用此项;"false
" 如果它应该在对象未选中时使用。android:state_activated 布尔值。"
true
" 如果在对象被激活为持久选择时应使用此项目(例如在持久导航视图中“突出显示”先前选择的列表项);"false
" 如果它应该在对象未激活时使用。在API 级别 11中引入。
我认为文档很清楚,所以有什么问题?
Here is other solution for this problem: 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.
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;
}
}
});