如何清除 ListView 选择?

2024-01-09

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

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

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

<?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>

(这是设置为我的列表视图的背景)

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

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

我尝试过这样做下列的 https://stackoverflow.com/questions/17751129/deselect-selected-item-in-listview,但没有取消选择。

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()
             }
        }

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

编辑:这是编辑文本的布局:

<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" />

编辑:这是列表视图的布局:

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

长话短说

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

TL/DR 解决方案

  • You can hide/remove selector with one of the following:
    • 使选择器透明getSelector().setAlpha(0)
    • 重置当前适配器setAdapter(myAdapter)(适配器可能是相同的)
  • Solutions that might or might not work, depending on the OS version:
    • 使列表视图完全刷新布局通过requestLayout(), invalidate() or forceLayout()方法;
    • 使列表视图刷新布局通过notifyDataSetChanged()

Theory

嗯,内置选择ListView乍一看非常棘手。然而,您应该记住两个主要区别,以避免像这样的混淆 - 列表视图selector and 选择模式.

列表视图选择器

ListView 选择器是一个可绘制资源,假设表示单击列表项的事件。您可以通过 XML 属性指定它android:listSelector https://developer.android.com/reference/android/widget/AbsListView.html#attr_android:listSelector或使用方法setSelector() https://developer.android.com/reference/android/widget/AbsListView.html#setSelector(int)。我在文档中找不到它,但我的理解是这个资源不应该是纯色的,因为在绘制它之后,如果视图没有发生巨大的变化(比如设置适配器,这反过来可能会导致它消失),它就不会消失。导致出现一些故障),因此此类可绘制对象应该仅在特定状态(例如android:state_pressed https://developer.android.com/reference/android/graphics/drawable/StateListDrawable.html#attr_android:state_pressed) 被申请;被应用。这是可用作列表视图选择器的可绘制对象的简单示例

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

无论出于何种原因,您都不能使用颜色状态列表 https://developer.android.com/guide/topics/resources/color-list-resource.html作为列表视图选择器,但仍然可以使用纯色(大多数情况下不合适)和州列表 https://developer.android.com/guide/topics/resources/drawable-resource.html#StateList绘图。这让事情变得有些混乱。 第一次单击列表视图后,您将无法轻松地从列表视图中删除列表视图选择器。

这里的主要思想是列表视图选择器并非旨在指示所选项目.

ListView选择模式

ListView 选择模式假设为表示选定的项目。您可能知道,我们在 ListView 中主要可以使用两种选择模式 - 单选和多选。它们允许跟踪分别选择的单行或多行。您可以通过设置它们android:choiceMode https://developer.android.com/reference/android/widget/AbsListView.html#attr_android:choiceModeXML 属性或setChoiceMode() https://developer.android.com/reference/android/widget/AbsListView.html#setChoiceMode(int)方法。 ListView 本身将选定的行保留在其中,并通过设置让他们知道在任何给定时刻选择了哪一行android:state_activated https://developer.android.com/reference/android/graphics/drawable/StateListDrawable.html#attr_android:state_activated行根视图的属性。为了使您的行反映这种状态,它们的根视图必须有相应的可绘制集,例如作为背景。这是此类可绘制的示例:

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

您可以使用以下命令以编程方式选择/取消选择行setItemChecked() https://developer.android.com/reference/android/widget/AbsListView.html#setItemChecked(int,%20boolean)方法。如果您希望 ListView 清除所有选定的项目,您可以使用clearChoices() https://developer.android.com/reference/android/widget/AbsListView.html#clearChoices()方法。您还可以使用以下方法系列检查选定的项目:getCheckedItemCount() https://developer.android.com/reference/android/widget/AbsListView.html#getCheckedItemCount(), getCheckedItemIds() https://developer.android.com/reference/android/widget/AbsListView.html#getCheckedItemIds(), getCheckedItemPosition() https://developer.android.com/reference/android/widget/AbsListView.html#getCheckedItemPosition()(对于单选模式),getCheckedItemPositions() https://developer.android.com/reference/android/widget/AbsListView.html#getCheckedItemPositions()(对于多项选择模式)

结论

如果你想让事情变得简单,不要使用列表视图选择器来指示所选项目.


解决问题

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

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

    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);
        }
    }

选项2.深思熟虑的方式

让我们检查一下您的代码并使其符合我逐步描述的规则。

修复 ListView 布局

在 ListView 布局中,选择器设置为纯色,因此当单击项目时,它们会随之着色。您用作 ListView 背景的可绘制对象没有影响,因为单击其行时 ListView 状态不会更改,因此您的 ListView 始终只有@color/windowBackground背景。

要解决您的问题,您需要首先从 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:listSelector="@color/colorPrimary"
    android:background="@color/windowBackground"
    android:choiceMode="singleChoice"/> 

让您的行反映激活状态

在评论中,您给出的适配器如下:

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

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

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

您只需指定相应的标准布局 - 使用的任何布局CheckedTextView https://developer.android.com/reference/android/widget/CheckedTextView.html 没有改变背景可绘制作为根组件或使用的根组件activatedBackgroundIndicator https://developer.android.com/reference/android/R.attr.html#activatedBackgroundIndicator作为他们的背景可绘制。对于您的情况,最合适的选项应该是simple_list_item_activated_1 https://android.googlesource.com/platform/frameworks/base/+/master/core/res/res/layout/simple_list_item_activated_1.xml。只需将其设置为您的ArrayAdapter https://developer.android.com/reference/android/widget/ArrayAdapter.html像这样的构造函数:

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

这个选项最接近我所理解的“标准”适配器。

2. 定制您的适配器

您可以使用标准布局和大多数标准适配器,但获取项目视图有一个小例外。只需引入一个匿名类并重写方法即可getView() https://developer.android.com/reference/android/widget/ArrayAdapter.html#getView(int,%20android.view.View,%20android.view.ViewGroup),提供具有相应背景可绘制的行视图:

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. 自定义布局

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

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

我把它保存在一个文件中/res/layout/list_view_item.xml不要忘记在适配器中设置此布局:

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

清算选择

之后,您的行将在单击时反映选定状态,并且您可以轻松清除行的选定状态ListView通过致电clearChoices()和后果requestLayout() https://developer.android.com/reference/android/view/View.html#requestLayout()要求 ListView 重绘自身。

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

    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) {}
    });

希望它有所帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何清除 ListView 选择? 的相关文章

随机推荐