在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.