Як динамічно оновлювати ListView на Android [закрито]


159

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

Я шукаю щось подібне:

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

7
Я висуваюсь на повторне відкриття. Я оновив текст, щоб зробити це питання більше, і це, очевидно, цінний ресурс спільноти, оскільки відповіді все ще надходять
Хамі

Повторіть запитання. Це явно корисно.
SilentNot

Відповіді:


286

По-перше, вам потрібно створити макет 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", передбачуваний текст, ймовірно, рекомендує "око". Поки користувач не обере або "око", або "око", ви 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);
}

7
Чи є якийсь простий спосіб фільтрувати ListView у "містить" замість "починається з" моди, як це рішення?
Віктор Брешан

12
Віктор - Якщо слова, які вас цікавлять, розділені пробілами, то це зробиться автоматично. Інакше не дуже. Напевно, найпростішим способом було б підкласифікувати адаптер, розширивши його, і замінити метод getFilter, щоб повернути визначений вами об'єкт Filter. Дивіться сторінку github.com/android/platform_frameworks_base/blob/master/core/…, щоб зрозуміти, як працює ArrayFilter за замовчуванням - було б просто скопіювати 95% цього коду та змінити рядки 479 і 486
Hamy

2
Хемі, відмінна запис! У мене є питання: я реалізував це, і після кожного листа, який я набираю, ListView зникає на пару секунд, а потім повертається, фільтрується. Чи відчували ви це? Моя інтуїція полягає в тому, що у мене є 600+ елементів у списку з нетривіальними функціями toString ().
lowellk

2
У альбомному режимі на меншому екрані клавіатура EditText + займає весь екран, а ListView не видно! Будь-яке рішення?
Мартін Конічек

4
Це справді потрібно? > Не забудьте видалити TextWatcher в OnDestroy ()
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); Яке виняток вищого рівня ви отримуєте? Цей код скопійовано з тестовою компіляцією, тому я, ймовірно, десь залишив хоча б одну помилку
Hamy

Привіт Хамі, ти вказав "@ + building_list / search_box" у коді з "filterText = (EditText) findViewById (R.id.search_box);" Тому мені було цікаво.
j7nn7k

1
Примусово закриваються при запуску введення. Частина помилки: ERROR / AndroidRuntime (188): java.lang.NullPointerException 02-11 07: 30: 29.828: ПОМИЛКА / AndroidRuntime (188): на xxx.com.ListFilter $ 1. onTextChanged (ListFilter.java:46) 02-11 07: 30: 29.828: ERROR / AndroidRuntime (188): на android.widget.TextView.sendOnTextChanged (TextView.java:6102) 02-11 07: 30: 29.828: ERROR / AndroidRuntime (188): на android.widget.TextView.handleTextChanged (TextView.java:6143) 02-11 07: 30: 29.828: ERROR / AndroidRuntime (188): at android.widget.TextView $ ChangeWatcher.onTextChanged (TextView : 6286)
j7nn7k

Johe, Oops - схоже, я намагався змінити код, щоб позбутися @ + building_list (тому що це пункт плутанини), але я його не сприймав скрізь. Дякую за пораду! Просто змінивши його на @ + id, слід це виправити
Хемі,

4

У мене виникла проблема з фільтруванням, результати були відфільтровані, але не відновлені !

тому перед фільтруванням (запуск діяльності) я створив резервну копію списку .. (просто інший список, що містить ті самі дані)

при фільтруванні фільтр і лист-адаптер підключаються до основного списку.

але сам фільтр використовував дані зі списку резервного копіювання.

це в моєму випадку забезпечило те, що список оновлювався негайно і навіть при видаленні символів пошукових термінів список успішно відновлюється у кожному випадку :)

спасибі за таке рішення все одно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.