Редактируемый список в Android

RecyclerView с редактируемым содержимым

Владельцам телефонов и планшетов

Товарищи, у меня есть просьба: пожалуйста, потестируйте приложение и отпишите мне, какую используете версию Android и насколько хорошо всё работает. Спасибо.

Начало

Всё началось с того, что на работе нужно сделать несколько списков с редактируемым содержимым. ListView не подходит по паре причин: он принимает фокус на свои элементы (не давая пользоваться текстовыми полями) и вообще устарел. Здесь я использовал RecyclerView.

Как работает RecyclerView

Он создаёт столько элементов, сколько умещается на экране, плюс небольшой запас. Как только пользователь начинает прокручивать список, элементы, вышедшие из зоны видимости, убираются с экрана, заполняются другим содержимым и ставятся в то место, где нужны новые. Если в элементах есть поля ввода, изменения, сделанные в них, не сохранятся, а затираются при переиспользовании вьюшек.

Самый очевидный вариант — это навешать TextWatcher'ов. Но вместо того, чтобы сохранять данные непрерывно, мне всё же хотелось бы делать это лениво, при необходимости. Так появляется две ситуации для сохранения: прокрутка (переиспользование элементов) и, собственно, момент, когда данные нужно сохранить.

Реализация

Добавим ViewHolder'у метод refresh, который вытащит содержимое из полей и положит в модели.

@Override
public void refresh() {
    mSampleModel.value = mSampleText.getText().toString();
    mSampleText.clearFocus();	// чтобы текстовые поля, будучи переиспользованными, появлялись без фокуса
}

Будем звать его, когда вьюха прячется и готовится к переиспользованию. В адаптере:

@Override
public void onViewRecycled(RecyclerView.ViewHolder holder) {
    ((SampleViewHolder) holder).refresh();
}

Теперь модели изчезающих видов исчезающих вьюшек будут обновляться. А у тех видов, которым после изменения текста посчастливилось выжить, нужно будет запросить данные непосредственно когда потребуется обновление моделей (перед сохранением, например).

LinearLayoutManager man = (LinearLayoutManager) mRecycler.getLayoutManager();
int i = man.findFirstVisibleItemPosition();
int end = man.findLastVisibleItemPosition();
if (i >= 0 && end >= 0) {
    while (i <= end) {
        ((SampleViewHolder) mRecycler.findViewHolderForAdapterPosition(i)).refresh();
        i++;
    }
}

Всё, хватаем модели и сохраняем.

Тестовое приложение

Скриншот

Я написал приложение для иллюстрации этой задачи. Надеюсь, что оно абсолютно адекватно, то есть:

Скачать тестовое приложение (разумеется, в настройках нужно разрешить ставить приложения из неизвестных источников)

Читать / стащить исходники

Changelog


← клик, если это интересно   |   ↓ место для вопросов и идей