如何在 Android 上动态更新 ListView

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1737009/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 03:33:15  来源:igfitidea点击:

How to dynamically update a ListView on Android

androidlistviewfilterandroid-widget

提问by Hamy

On Android, how can I a ListViewthat filters based on user input, where the items shown are updated dynamically based on the TextViewvalue?

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

I'm looking for something like this:

我正在寻找这样的东西:

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

回答by Hamy

First, you need to create an XML layout that has both an EditText, and a ListView.

首先,您需要创建一个同时具有 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>

This will lay everything out properly, with a nice EditText above the ListView. Next, create a ListActivity as you would normally, but add a setContentView()call in the onCreate()method so we use our recently declared layout. Remember that we ID'ed the ListViewspecially, with android:id="@android:id/list". This allows the ListActivityto know which ListViewwe want to use in our declared layout.

这将正确布置所有内容,在 ListView 上方有一个不错的 EditText。接下来,像往常一样创建一个 ListActivity,但setContentView()onCreate()方法中添加一个调用,以便我们使用我们最近声明的布局。请记住,我们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());
    }

Running the app now should show your previous ListView, with a nice box above. In order to make that box do something, we need to take the input from it, and make that input filter the list. While a lot of people have tried to do this manually, mostListViewAdapterclasses come with a Filterobject that can be used to perform the filtering automagically. We just need to pipe the input from the EditTextinto the Filter. Turns out that is pretty easy. To run a quick test, add this line to your onCreate()call

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

adapter.getFilter().filter(s);

Notice that you will need to save your ListAdapterto a variable to make this work - I have saved my ArrayAdapter<String>from earlier into a variable called 'adapter'.

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

Next step is to get the input from the EditText. This actually takes a bit of thought. You could add an OnKeyListener()to your EditText. However, this listener only receives some key events. For example, if a user enters 'wyw', the predictive text will likely recommend 'eye'. Until the user chooses either 'wyw' or 'eye', your OnKeyListenerwill not receive a key event. Some may prefer this solution, but I found it frustrating. I wanted every key event, so I had the choice of filtering or not filtering. The solution is a TextWatcher. Simply create and add a TextWatcherto the EditText, and pass the ListAdapterFiltera filter request every time the text changes. Remember to remove the TextWatcherin OnDestroy()! Here is the final solution:

下一步是从EditText. 这实际上需要一些思考。你可以OnKeyListener()在你的EditText. 然而,这个监听器只接收一些关键事件。例如,如果用户输入“wyw”,则预测文本可能会推荐“eye”。在用户选择“wyw”或“eye”之前,您OnKeyListener将不会收到关键事件。有些人可能更喜欢这个解决方案,但我发现它令人沮丧。我想要每个关键事件,所以我可以选择过滤或不过滤。解决方案是一个TextWatcher. 只需创建并添加 aTextWatcherEditText,并在ListAdapterFilter每次文本更改时传递过滤器请求。记得把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);
}

回答by j7nn7k

running the programm will cause a force close.

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

I swaped the line:

我换了线:

android:id="@+building_list/search_box"

android:id="@+building_list/search_box"

with

android:id="@+id/search_box"

android:id="@+id/search_box"

could that be the problem? What is the '@+building_list' for?

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

回答by cV2

i had a problem with filtering, that results have been filtered, but not restored!

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

so before filtering (activity start) i created a list backup.. (just another list, containing the same data)

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

on filtering, the filter and listadapter is connected to the primary list.

在过滤时,过滤器和列表适配器连接到主列表。

but the filter itself used the data from the backuped list.

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

this ensured in my case, that the list was updated immediately and even on deleting search-term-characters the list gets restored successfully in every case :)

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

thanks for this solution anyways.

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