如何清除 ListView 选择? [英] How do I clear ListView selection?

查看:51
本文介绍了如何清除 ListView 选择?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

<块引用>

TL;DR:您从 (a) 我的列表视图中选择一个选项.然后,您改变主意并在 (b) 我的编辑文本中输入一些内容.如何清除您的列表视图选择并仅显示您的编辑文本?(反之亦然)

我有一个带有选项列表视图的应用程序以及一个用于创建自己的选项的编辑文本.我需要用户选择或创建一个选项,但不能同时选择.这是我的布局图:

每当用户从列表视图中选择一个选项时,我都会将其设置为已选择",将其设为绿色,如下所示:

</选择器>

(这是我的listview的背景)

问题:如果用户决定输入他们自己的选项,我想取消选择列表视图选项,因为他们只能有一个选项.

  1. 用户从列表视图中选择一个选项
  2. 用户决定使用编辑文本创建自己的选项
  3. 当他们开始输入自己的内容时,列表视图选项未被选中

我尝试过以下,但没有取消选择.

e.setOnEditorActionListener(new TextView.OnEditorActionListener(){public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {for(int i=0; i<=5; i++){listView.setItemChecked(i, false);}listView.clearChoices();listView.requestLayout()适配器.notifyDataSetChanged()}}

一个非常令人费解的困境,感谢任何帮助!

这里是编辑文本的布局:

这里是列表视图的布局:

 </ListView>

解决方案

长话短说

  • ListView 选择器 (android:listSelector) 旨在指示点击事件,但未选择项目.
  • 如果绘制了一个 ListView 选择器(在第一次点击之后),它不会消失而不会在 ListView 中发生剧烈变化
  • 因此,如果没有将状态作为 ListView 选择器应用于它,则仅使用具有透明背景的可绘制对象.不要为它使用纯色资源,不要混淆自己.
  • 使用 ListView 选择模式 (android:choiceMode) 来指示所选项目.
  • ListView 通过在行的根视图上设置 android:state_activated 来告诉选择了哪一行.为您的适配器提供相应的布局/视图以正确表示所选项目.

理论

好吧,ListView 中的内置选择乍一看非常棘手.但是,您应该记住两个主要区别,以避免出现这样的混淆 - 列表视图选择器选择模式.

ListView 选择器

ListView 选择器是一种可绘制资源,假定指示单击列表项的事件.您可以通过 XML-property android 指定它:listSelector 或使用方法 <代码>setSelector().我在文档中找不到它,但我的理解是这个资源不应该是纯色,因为在它被绘制后,它不会在视图中没有急剧变化的情况下消失(比如设置一个适配器,反过来可能导致出现一些故障),因此此类可绘制对象仅在特定状态下才可见(例如 android:state_pressed) 已应用.这是可用作列表视图选择器的可绘制对象的简单示例

<项目android:state_pressed="true"android:drawable="@android:color/darker_gray";/><项目android:drawable="@android:color/transparent";/></选择器>

无论出于何种原因,您都不能使用颜色状态列表 作为列表视图选择器,但仍然可以使用纯色(通常是不合适的)和 状态列表 可绘制对象.这让事情有些混乱.第一次单击列表视图后,您将无法轻松地从列表视图中删除列表视图选择器.

这里的主要思想是列表视图选择器不是为了指示所选项目.

ListView 选择模式

ListView 选择模式假定为指示所选项目.您可能知道,主要有两种我们可以在 ListView 中使用的选择模式 - 单选和多选.它们允许跟踪分别选择的单行或多行.您可以通过 android:choiceMode XML 属性或 setChoiceMode() 方法.ListView 本身在其中保留选定的行,并通过设置 android:state_activated 行根视图的属性.为了使您的行反映此状态,它们的根视图必须具有相应的可绘制集,例如作为背景.这是此类可绘制对象的示例:

<项目机器人:state_activated =真";android:drawable=@android:color/holo_green_light"/><项目android:drawable="@android:color/transparent";/></选择器>

您可以使用 setItemChecked() 方法.如果您希望 ListView 清除所有选定的项目,您可以使用 clearChoices() 方法.您还可以使用系列方法检查所选项目:<代码>getCheckedItemCount(), getCheckedItemIds(), getCheckedItemPosition()(单选模式),getCheckedItemPositions()(多选模式)

结论

如果您想保持简单,不要使用列表视图选择器来指示所选项目.


解决问题

选项 1. 脏修复 - 隐藏选择器

我们可以在需要时隐藏选择器可绘制,而不是实际删除选择器、更改布局和实现健壮的方法,并在稍后单击 ListView 项时显示它:

 public void hideListViewSelector() {mListView.getSelector().setAlpha(0);}@覆盖public void onItemClick(AdapterView<?> parent, View view, int position, long id) {如果 (mListView.getSelector().getAlpha() == 0) {mListView.getSelector().setAlpha(255);}}

选项 2. 周到的方式

让我们检查一下你的代码,让它符合我一步一步描述的规则.

修复 ListView 布局

在您的 ListView 布局中,选择器设置为纯色,因此您的项目在单击时会被它着色.您用作 ListView 背景的 drawable 没有影响,因为单击其行时 ListView 状态不会改变,因此您的 ListView 始终只有 @color/windowBackground 背景.

要解决您的问题,您首先需要从 ListView 布局中删除选择器:

<块引用>

android:listSelector="@color/colorPrimary"android:background="@color/windowBackground"android:choiceMode="singleChoice"/>

让你的行反映激活状态

在评论中你给你的适配器如下:

final ArrayAdapter适配器 = 新的 ArrayAdapter<>(this, android.R.layout.simple_list_item_1, text1, listOfThings);

您还问我是否可以继续使用标准适配器来实现所需的行为.我们可以肯定,但无论如何都需要进行一些更改.对于这种情况,我可以看到 3 个选项:

1.使用标准的 android 检查布局

您可以指定相应的标准布局 - 任何使用 CheckedTextView 没有改变背景可绘制 作为根组件或那些使用 activatedBackgroundIndicator 作为它们的可绘制背景.对于您的情况,最合适的选项应该是 simple_list_item_activated_1.只需将其设置为您的 ArrayAdapter像这样的构造函数:

final ArrayAdapter适配器 = 新 ArrayAdapter(this, android.R.layout.simple_list_item_activated_1, android.R.id.text1, listOfThings);

这个选项最接近我对标准"适配器的理解.

2.自定义您的适配器

您可以使用标准布局和大多数标准适配器,但有一个小例外,即获取您的项目的视图.只需引入一个匿名类并覆盖方法 getView(),提供具有相应背景可绘制的行视图:

final ArrayAdapter适配器 = 新 ArrayAdapter(this, android.R.layout.simple_list_item_1, android.R.id.text1, listOfThings) {@非空@覆盖public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {最终视图视图 = super.getView(position, convertView, parent);if (convertView == null) {view.setBackgroundResource(R.drawable.list_item_bg);}返回视图;}};

3.自定义布局

解决这个问题的最常见方法当然是为项目视图引入您自己的布局.这是我的简单示例:

<文本视图android:id="@android:id/text1";android:layout_width="wrap_content";android:layout_height=wrap_content"/></FrameLayout>

我把它保存在一个文件 /res/layout/list_view_item.xml 别忘了在你的适配器中设置这个布局:

final ArrayAdapter适配器 = 新 ArrayAdapter(this, R.layout.list_view_item, android.R.id.text1, listOfThings);

清除选择

之后,您的行将在单击时反映选定状态,您可以通过调用 clearChoices() 和结果 ListView 的选定状态href="https://developer.android.com/reference/android/view/View.html#requestLayout()" rel="nofollow noreferrer">requestLayout() 询问重绘自身的 ListView.

这里有一点评论,如果您想在用户开始输入时取消选择项目,而不是在他实际单击返回(完成)按钮时取消选择,则需要使用 TextWatcher 回调:

 mEditText.addTextChangedListener(new TextWatcher(){@覆盖public void beforeTextChanged(CharSequence s, int start, int count, int after) {}@覆盖public void onTextChanged(CharSequence s, int start, int before, int count) {如果 (mListView.getCheckedItemCount() > 0) {mListView.clearChoices();mListView.requestLayout();}}@覆盖public void afterTextChanged(Editable s) {}});

希望它有所帮助.

TL;DR: You choose an option from (a) my listview. Then, you change your mind and type something in (b) my edit text. How do I clear your listview selection and only show your edittext? (and vice versa)

I have an application with a listview of options as well as an edittext to create an own option. I need the user to either choose or create an option, but not both. Here's a drawing of my layout:

Whenever the user selects an option from the listview, I set it as "selected" by making it green, like so:

<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:state_selected="true"
        android:drawable="@color/colorPrimary"/>
    <item
        android:state_selected="false"
        android:drawable="@color/windowBackground" />
</selector>

(this is set as the background of my listview)

Problem: I want to unselect the listview option if the user decides to type in their own option since they can only have one option.

  1. User selects an option from the listview
  2. User decides they want to create their own option using the edittext
  3. The listview option is unselected when they start typing their own

I've tried doing the following, but nothing unselects.

e.setOnEditorActionListener(new TextView.OnEditorActionListener()
        {
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {

                for(int i=0; i<=5; i++){
                                listView.setItemChecked(i, false);
                }
                listView.clearChoices();
                listView.requestLayout()
                adapter.notifyDataSetChanged()
             }
        }

A very puzzling predicament, any help is appreciated!

Edit: here is the layout of the edittext:

<EditText
                android:id="@+id/editText"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignBaseline="@+id/textView4"
                android:layout_alignBottom="@+id/textView4"
                android:layout_toEndOf="@+id/textView4"
                android:layout_toRightOf="@+id/textView4"
                android:color="@color/colorPrimary"
                android:imeOptions="actionDone"
                android:inputType="text"
                android:textColor="@color/textColorPrimary"
                android:textColorHint="@color/colorPrimary" />

Edit: here is the layout of the listview:

    <ListView
        android:id="@+id/listview"
        android:layout_width="wrap_content"
        android:layout_height="250dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_below="@+id/toolbar"
        android:background="@drawable/bg_key"
        android:choiceMode="singleChoice"
        android:listSelector="@color/colorPrimary">

    </ListView>

解决方案

Long Story Short

  • ListView selector (android:listSelector) is designed to indicate a click event, but not selected items.
  • If a ListView selector is drawn (after first click) it won't dissapear without drastic changes in the ListView
  • Hence use only drawables with transparent background if no state is applied to it as a ListView selector. Don't use a plain color resource for it, don't confuse yourself.
  • Use ListView choice mode (android:choiceMode) to indicate selected items.
  • ListView tells which row is selected by setting android:state_activated on the row's root view. Provide your adapter with corresponding layout/views to represent selected items correctly.

Theory

Well, the built-in selection in ListView is utterly tricky at a first glance. However there are two main distinctions you should keep in mind to avoid confusing like this - list view selector and choice mode.

ListView selector

ListView selector is a drawable resource that is assumed to indicate an event of clicking a list item. You can specify it either by XML-property android:listSelector or using method setSelector(). I couldn't find it in docs, but my understanding is that this resource should not be a plain color, because after it's being drawn, it won't vanish without drastic changes in the view (like setting an adapter, that in turn may cause some glitches to appear), hence such drawable should be visible only while particular state (e.g. android:state_pressed) is applied. Here is a simple example of the drawable that can be used as a List View selector

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:state_pressed="true"
        android:drawable="@android:color/darker_gray" />
    <item
        android:drawable="@android:color/transparent" />
</selector>

For whatever reason you cannot use a Color State List as List View selector, but still can use plain colors (that are mostly inappropriate) and State List drawables. It makes things somewhat confusing. After the first click on a List View happens, you will not be able to remove List View selector from the List View easily.

The main idea here is that List View selector is not designed to indicate selected item.

ListView choice mode

ListView choice mode is assumed to indicate selected items. As you might know, primarily there are two choice modes we can use in ListView - Single Choice and Multiple Choice. They allow to track a single or multiple rows selected respectively. You can set them via android:choiceMode XML-property or setChoiceMode() method. The ListView itself keeps selected rows in it and let them know which one is selected at any given moment by setting android:state_activated property of the row root view. In order to make your rows reflect this state, their root view must have a corresponding drawable set, e.g. as a background. Here is an example of such drawable:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:state_activated="true"
        android:drawable="@android:color/holo_green_light" />
    <item
        android:drawable="@android:color/transparent" />
</selector>

You can make rows selected/deselected programmatically using the setItemChecked() method. If you want a ListView to clear all selected items, you can use the clearChoices() method. You also can check selected items using the family of the methods: getCheckedItemCount(), getCheckedItemIds(), getCheckedItemPosition() (for single choice mode), getCheckedItemPositions() (for multiple choice mode)

Conclusion

If you want to keep things simple, do not use the List View selector to indicate selected items.


Solving the issue

Option 1. Dirty fix - hide selector

Instead of actually removing selector, changing layouts and implementing a robust approach, we can hide the selector drawable when it's needed and show it later when clicking a ListView item:

    public void hideListViewSelector() {
        mListView.getSelector().setAlpha(0);
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        if (mListView.getSelector().getAlpha() == 0) {
            mListView.getSelector().setAlpha(255);
        }
    }

Option 2. Thoughtful way

Let's go through your code and make it comply the rules i described step by step.

Fix ListView layout

In your ListView layout the selector is set to a plain color, and therefore your items are colored by it when they are clicked. The drawable you use as the ListView background have no impact, because ListView state doesn't change when its rows are clicked, hence your ListView always has just @color/windowBackground background.

To solve your problem you need at first remove the selector from the ListView layout:

<ListView
    android:id="@+id/listview"
    android:layout_width="wrap_content"
    android:layout_height="250dp"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_below="@+id/toolbar"
    android:listSelector="@color/colorPrimary"
    android:background="@color/windowBackground"
    android:choiceMode="singleChoice"/> 

Make your rows reflect activated state

In the comments you give your adapter as follows:

final ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, text1, listOfThings);

You also asked me if it's possible to keep using standard adapter to achieve desired behavior. We can for sure, but anyway a few changes are required. I can see 3 options for this case:

1. Using standard android checked layout

You can just specify a corresponding standard layout - either any of the layouts that use CheckedTextView without changed background drawable as the root component or of those that use activatedBackgroundIndicator as their background drawable. For your case the most appropriate option should be the simple_list_item_activated_1. Just set it as in your ArrayAdapter constructor like this:

final ArrayAdapter<String> adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_activated_1, android.R.id.text1, listOfThings);

This option is the closest to what i understand by 'standard' adapter.

2. Customize your adapter

You can use standard layout and mostly standard adapter with a small exception of getting a view for your items. Just introduce an anonymous class and override the method getView(), providing row views with corresponding background drawable:

final ArrayAdapter<String> adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, android.R.id.text1, listOfThings) {

    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        final View view = super.getView(position, convertView, parent);
        if (convertView == null) {
            view.setBackgroundResource(R.drawable.list_item_bg);
        }
        return view;
    }
};

3. Customize your layout

The most common way of addressing this issue is of course introducing your own layout for the items view. Here is my simple example:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="@drawable/list_item_bg"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:padding="16dp">

    <TextView
        android:id="@android:id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</FrameLayout>

I saved it in a file /res/layout/list_view_item.xml Do not forget setting this layout in your adapter:

final ArrayAdapter<String> adapter = new ArrayAdapter(this, R.layout.list_view_item, android.R.id.text1, listOfThings);

Clearing selection

After that your rows will reflect selected state when they are clicked, and you can easily clear the selected state of your ListView by calling clearChoices() and consequence requestLayout() to ask the ListView to redraw itself.

One little comment here that if you want unselect the item when user start typing, but not when he actually clicks the return (done) button, you need to use a TextWatcher callback instead:

    mEditText.addTextChangedListener(new TextWatcher(){

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            if (mListView.getCheckedItemCount() > 0) {
                mListView.clearChoices();
                mListView.requestLayout();
            }
        }

        @Override
        public void afterTextChanged(Editable s) {}
    });

Hopefully, it helped.

这篇关于如何清除 ListView 选择?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆