如何在Android上动态更新ListView [关闭]


159

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

我正在寻找这样的东西:

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

7
我提名重新开放。我已经更新了文字,使之成为一个问题,它显然是宝贵的社区资源,因为答案仍在不断涌现
Hamy 2014年

请重新打开问题。这显然是有帮助的。
SilentNot

Answers:


286

首先,您需要创建一个同时具有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,但是setContentView()onCreate()方法中添加一个调用,以便我们使用我们最近声明的布局。请记住,我们ListView特别对ID进行了编号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<String>以前的代码保存到了名为“ adapter”的变量中。

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

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

7
是否有任何直接的方法可以像这种解决方案那样以“包含”方式过滤ListView而不是“以...开头”方式?
维克多·布雷桑(ViktorBrešan)2010年

12
Viktor-如果您感兴趣的单词用空格隔开,则它将自动执行此操作。否则,不是真的。可能最简单的方法是通过扩展Adapter来继承Adapter的子类,并重写getFilter方法以返回您定义的Filter对象。请参阅github.com/android/platform_frameworks_base/blob/master/core/…了解默认ArrayFilter的工作原理-复制此代码的95%并更改479和486行非常简单
Hamy

2
哈米,出色的写作!不过,我有一个问题:我已经实现了这一点,在我键入的每个字母之后,ListView消失了几秒钟,然后又返回并进行了过滤。你有没有经历过?我的直觉是这是因为列表中有600多个项目,并且具有非平凡的toString()函数。
lowellk 2011年

2
在较小屏幕的横向模式下,EditText +键盘占据整个屏幕,并且ListView不可见!有什么办法吗?
Martin Konicek 2011年

4
这真的有必要吗?>请记住要删除OnDestroy()中的TextWatcher
Jojo

10

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

我换了一行:

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); 您得到的顶级例外是什么?这段代码是通过w / oa测试编译程序复制的,因此我很可能在某个地方留下了至少一个错误
Hamy 2010年

嗨,哈米,您在代码中使用“ filterText =(EditText)findViewById(R.id.search_box);”引用了代码中的“ @ + building_list / search_box”;这就是为什么我想知道。
j7nn7k 2010年

1
开始输入时,forceclose发生错误。错误的一部分: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:错误/ AndroidRuntime(188):位于android.widget.TextView.handleTextChanged(TextView.java:6143)02-11 07:30:29.828:错误/ AndroidRuntime(188):位于android.widget.TextView $ ChangeWatcher.onTextChanged(TextView.java :6286)
j7nn7k

Johe,糟糕-似乎我正在尝试修改代码以摆脱@ + building_list(因为这很令人困惑),但是我并没有到处都看到它。谢谢你的提示!只需将其更改为@ + id即可解决
Hamy 2010年

4

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

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

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

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

就我而言,这确保了列表可以立即更新,甚至在删除搜索字词时,列表在每种情况下都可以成功恢复:)

无论如何,感谢您的解决方案。

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.