【问题标题】:How to dynamically update a ListView on Android [closed]如何在 Android 上动态更新 ListView [关闭]
【发布时间】:2010-12-16 18:12:34
【问题描述】:

在 Android 上,ListView 如何根据用户输入进行过滤,其中显示的项目根据 TextView 值动态更新?

我正在寻找这样的东西:

-------------------------
| Text View             |
-------------------------
| List item             |
| List item             |
| List item             |
| List item             |
|                       |
|                       |
|                       |
|                       |
-------------------------

【问题讨论】:

  • 我提名重新开放。我已经更新了文本,使其更像一个问题,它显然是一个有价值的社区资源,因为答案仍在不断涌现
  • 请重新打开问题。这显然很有帮助。

标签: android listview filter android-widget


【解决方案1】:

首先,您需要创建一个同时具有 EditText 和 ListView 的 XML 布局。

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <!-- Pretty hint text, and maxLines -->
    <EditText android:id="@+building_list/search_box" 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:hint="type to filter"
        android:inputType="text"
        android:maxLines="1"/>

    <!-- Set height to 0, and let the weight param expand it -->
    <!-- Note the use of the default ID! This lets us use a 
         ListActivity still! -->
    <ListView android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="0dip"
        android:layout_weight="1" 
         /> 

</LinearLayout>

这将正确布置所有内容,在 ListView 上方有一个漂亮的 EditText。接下来,像往常一样创建一个 ListActivity,但在 onCreate() 方法中添加一个 setContentView() 调用,以便我们使用我们最近声明的布局。请记住,我们特意将ListView 标识为android:id="@android:id/list"。这允许ListActivity 知道我们要在声明的布局中使用哪个ListView

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.filterable_listview);

        setListAdapter(new ArrayAdapter<String>(this,
                       android.R.layout.simple_list_item_1, 
                       getStringArrayList());
    }

现在运行应用程序应该会显示您以前的ListView,上面有一个漂亮的框。为了让那个盒子做点什么,我们需要从中获取输入,并让那个输入过滤列表。虽然很多人尝试手动执行此操作,但大多数 ListView Adapter 类带有一个 Filter 对象,可用于自动执行过滤。我们只需要将输入从EditText 传送到Filter。事实证明这很容易。要运行快速测试,请将此行添加到您的 onCreate() 调用中

adapter.getFilter().filter(s);

请注意,您需要将 ListAdapter 保存到一个变量中才能完成这项工作 - 我已将之前的 ArrayAdapter&lt;String&gt; 保存到一个名为“适配器”的变量中。

下一步是从EditText 获取输入。这实际上需要一些思考。您可以将OnKeyListener() 添加到您的EditText。然而,这个监听器只接收一些关键事件。例如,如果用户输入“wyw”,则预测文本可能会推荐“eye”。在用户选择“wyw”或“eye”之前,您的OnKeyListener 将不会收到关键事件。有些人可能更喜欢这个解决方案,但我发现它令人沮丧。我想要每个关键事件,所以我可以选择过滤或不过滤。解决方案是TextWatcher。只需创建一个TextWatcher 并将其添加到EditText,并在每次文本更改时传递ListAdapter Filter 一个过滤器请求。记得删除OnDestroy()中的TextWatcher!这是最终的解决方案:

private EditText filterText = null;
ArrayAdapter<String> adapter = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.filterable_listview);

    filterText = (EditText) findViewById(R.id.search_box);
    filterText.addTextChangedListener(filterTextWatcher);

    setListAdapter(new ArrayAdapter<String>(this,
                   android.R.layout.simple_list_item_1, 
                   getStringArrayList());
}

private TextWatcher filterTextWatcher = new TextWatcher() {

    public void afterTextChanged(Editable s) {
    }

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

    public void onTextChanged(CharSequence s, int start, int before,
            int count) {
        adapter.getFilter().filter(s);
    }

};

@Override
protected void onDestroy() {
    super.onDestroy();
    filterText.removeTextChangedListener(filterTextWatcher);
}

【讨论】:

  • 有什么直接的方法可以像这个解决方案那样以“包含”而不是“开始”的方式过滤 ListView?
  • Viktor - 如果您感兴趣的单词用空格分隔,那么它会自动执行此操作。否则,不是真的。可能最简单的方法是通过扩展 Adapter 子类化它,并覆盖 getFilter 方法以返回您定义的 Filter 对象。请参阅github.com/android/platform_frameworks_base/blob/master/core/… 以了解默认 ArrayFilter 的工作原理 - 复制 95% 的代码并更改第 479 和 486 行会很简单
  • 哈米,写得很好!不过我有一个问题:我已经实现了这个,并且在我输入每个字母之后,ListView 消失了几秒钟,然后又回来了,被过滤了。你有过这种经历吗?我的直觉是,这是因为我在列表中有 600 多个项目,具有非平凡的 toString() 函数。
  • 在小屏幕横向模式下,EditText + 键盘占据整个屏幕,ListView 不可见!有什么解决办法吗?
  • 这真的有必要吗? > 记得在 OnDestroy() 中移除 TextWatcher
【解决方案2】:

运行程序将导致强制关闭。

我换行了:

android:id="@+building_list/search_box"

android:id="@+id/search_box"

这可能是问题吗? '@+building_list' 是干什么用的?

【讨论】:

  • Johe,当你说 R.id.something 时,id 中存在某物,因为你说的是​​ android:id="@+id/search_box"。如果你说 android:id="@+building_list/search_box" 那么在代码中你可以调用 findViewById(R.building_list.search_box);你得到的顶级异常是什么?这段代码是在没有测试编译的情况下复制的,所以我可能在某处留下了至少一个错误
  • 嗨,Hamy,您在代码中使用“filterText = (EditText) findViewById(R.id.search_box);”引用了“@+building_list/search_box”这就是我想知道的原因。
  • 开始输入时发生强制关闭。部分错误:ERROR/AndroidRuntime(188): java.lang.NullPointerException 02-11 07:30:29.828: ERROR/AndroidRuntime(188):在 xxx.com.ListFilter$1.onTextChanged(ListFilter.java:46) 02-11 07:30:29.828: 错误/AndroidRuntime(188): 在 android.widget.TextView.sendOnTextChanged(TextView.java:6102) 02-11 07:30:29.828: ERROR/AndroidRuntime(188): at android.widget.TextView.handleTextChanged(TextView.java:6143) 02-11 07:30:29.828: ERROR/AndroidRuntime(188): at android.widget.TextView $ChangeWatcher.onTextChanged(TextView.java:6286)
  • Johe,哎呀 - 看起来我试图修改代码以摆脱 @+building_list (因为这是一个混淆点)但我没有在任何地方都抓住它。谢谢你的提示!只需将其更改为 @+id 即可修复它
【解决方案3】:

我遇到了过滤问题, 结果已被过滤,但未恢复

所以在过滤(活动开始)之前,我创建了一个列表备份.. (只是另一个列表,包含相同的数据)

过滤时,过滤器和listadapter连接到主列表。

但过滤器本身使用了备份列表中的数据。

在我的情况下,这确保了列表会​​立即更新,甚至在删除搜索词字符时,列表在每种情况下都会成功恢复:)

无论如何感谢这个解决方案。

【讨论】:

    猜你喜欢
    • 2013-11-28
    • 2012-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多