在Android中选择,检查和激活的状态之间有什么区别?


Answers:


182

Checked和Activated之间的区别实际上非常有趣。甚至Google文档都道歉(在下面添加了重点):

...例如,在启用了一个或多个选择的列表视图中,当前选择集中的视图被激活。(嗯,是的,我们对这里的术语深感抱歉。)激活状态会向下传播到设置了该视图的子级。

所以这是区别:

  1. 激活是在Honeycomb中引入的,因此您在此之前不能使用它
  2. 现在,激活是每个视图的属性。它具有setActivated()和isActivated()方法
  3. 激活后会传播到设置了该视图的View的子级
  4. Checked围绕实现Checkable接口的View。方法setChecked(),isChecked(),toggle()
  5. 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()。

  6. 在Honeycomb之前,我们必须实施变通办法以在列表项中反映state_checked。这是因为ListView仅在布局中最顶层的View上调用setChecked()(并且布局不实现可检查的)...并且它不会在没有帮助的情况下传播。这些变通办法采用以下形式:扩展根布局以实现Checkable。在其构造函数中,递归查找实现Checkable的所有子代。调用setChecked()等时,将调用传递给那些View。如果那些视图使用state_checked的不同可绘制对象来实现状态列表可绘制对象(例如CheckBox),则选中的状态将反映在UI中。

  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接口。然后,您需要通过实现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"/>

...,在RelativeLayout中结合state_checked实现Checkable的代码可能是:

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布局等之前先阅读一下。非常感谢。
布莱克·芒福德2014年

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.) 来源
woojoo666 2014年

使用上面发布的蜂窝后方法时,我的自定义背景颜色仅显示在选定/重点突出的项目后面,而不显示在选中的项目后面:调用setItemChecked(),然后使用具有属性的选择器android:state_activated="true"
woojoo666 2014年

1
非常感谢,我浪费了三天的时间来弄清楚这个问题,直到我最终决定问自己“选中,选中和激活之间有什么区别”,糟透了,处理菜单这样简单的事情必须如此复杂,过度设计对于Google的天才们来说,这似乎是该公司故意放慢其他公司的障碍。
古巴创(Gubatron),2015年

20

根据文档

  • android:state_selected 布尔值。“ true”,如果在使用方向控件进行导航时(例如,使用d-pad浏览列表时),当对象是当前用户选择时应使用此项目;false如果在未选择对象时应使用此项目,则为“ ”。当焦点(android:state_focused)不够时(例如,列表视图具有焦点并且使用d-pad选择其中的一个项目时),将使用选定状态。

  • android:state_checked 布尔值。“ true”,如果在检查对象时应使用此项;false如果在取消选中对象时应使用“ ”。

  • android:state_activated 布尔值。“ true”(如果在激活对象作为持久选择时应使用此项目,例如在持久导航视图中“突出显示”先前选择的列表项);“ false”(如果在未激活对象时应使用它)。在API级别11中引入。

我认为文档非常清楚,这是什么问题?


5
您能否详细说明android:state_selected。设置为true的情况是什么?
安徒生

@Anderson取决于您使用的ViewGroup-ListView,RecyclerView(可能是其LayoutManagers),GridView可能具有不同的实现:ListView调用setFocused,其中GridView调用setSelected。可能只是在不同平台版本上检查您的应用程序的情况。
2015年

1
@Anderson:如果您有一个列表,并且用户具有箭头键,则“选择”一个,然后当他们向上/向下箭头时,选择将向上/向下移动。当他们按下“激活”键时,它“激活”该控件,将其选择与鼠标悬停大致相同,而将检查/激活与单击几乎相同。
Mooing Duck 2015年

我想知道,我将使用Activate突出显示列表视图中的一个项目,但是是否将其他列表项目的Activate设置为false……如果不这样做,那么我就不必查找另一个激活的子项并将激活设置为false?
Lion789

0

这是此问题的其他解决方案:https : //github.com/jiahaoliuliu/CustomizedListRow/blob/master/src/com/jiahaoliuliu/android/customizedlistview/MainActivity.java

我已经重写了setOnItemClickListener方法,并在代码中检查了不同的情况。但绝对地,Marvin的解决方案要好得多。

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;
    }
    }
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.