Как динамически обновлять ListView на Android

На Android, как я могу ListView фильтровать на основе ввода пользователя, где отображаемые элементы обновляются динамически на основе значения TextView?

Я ищу что-то вроде этого:

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

Ответ 1

Сначала вам нужно создать XML-макет, который имеет как EditText, так и ListView.

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

Это заложит все правильно, с хорошим EditText над ListView. Затем создайте 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());
    }

Запуск приложения теперь должен показывать предыдущий ListView, с хорошим полем выше. Чтобы сделать этот блок что-то, нам нужно взять его от него и сделать этот входным фильтром список. Хотя многие люди пытались сделать это вручную, большинство классов ListView Adapter имеют объект Filter, который можно использовать для автоматической фильтрации. Нам просто нужно подключить вход от EditText к Filter. Оказывается, это довольно легко. Чтобы выполнить быстрый тест, добавьте эту строку в свой вызов onCreate()

adapter.getFilter().filter(s);

Обратите внимание, что вам нужно будет сохранить ваш ListAdapter в переменной, чтобы сделать эту работу. Я сохранил мой ArrayAdapter<String> ранее в переменной с именем "адаптер".

Следующий шаг - получить вход от EditText. Это на самом деле задумывается. Вы можете добавить OnKeyListener() к вашему EditText. Однако этот слушатель получает только некоторые ключевые события. Например, если пользователь вводит "wyw", предсказательный текст, скорее всего, порекомендует "глаз". Пока пользователь не выберет "wyw" или "eye", ваш OnKeyListener не получит ключевое событие. Некоторые могут предпочесть это решение, но я счел это расстраивающим. Я хотел каждое ключевое событие, поэтому у меня был выбор фильтрации или не фильтрации. Решение имеет вид TextWatcher. Просто создайте и добавьте TextWatcher в EditText и передайте ListAdapter Filter запрос фильтра каждый раз, когда текст изменится. Не забудьте удалить TextWatcher в 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);
}

Ответ 2

запуск программы приведет к силе закрытия.

Я поменял строку:

Android: ID = "@+ building_list/search_box"

с

андроид: идентификатор = "@+ идентификатор /search _box"

Может быть, проблема? Что такое "@+ building_list" для?

Ответ 3

У меня была проблема с фильтрацией, что результаты были отфильтрованы, но не восстановлен!

поэтому перед фильтрацией (началом активности) я создал резервную копию списка. (только один список, содержащий те же данные)

при фильтрации, фильтр и listadapter подключены к основному списку.

но сам фильтр использовал данные из резервного списка.

это обеспечило в моем случае, что список был обновлен сразу и даже при удалении символов поискового термина список успешно восстанавливается в каждом случае:)

спасибо за это решение в любом случае.