ListView с разными Item типами

ListView с разными Item типами

Отображение списков в Android можно реализовать с помощью ListView компонента. Иногда возникает необходимость использовать разные типы элементов списка, которые различаются разметкой, ролью, поведением и так далее. Например, нужно разделить список на секции с соответствующими заголовками, в одном элементе нужно отображать количество новых сообщений, а в другом должен быть CheckBox компонент. В некоторых случаях подходит ExpandableListView, но при этом может не подходить его поведение, а именно разворачивание и сворачивание групп при нажатии. Так же не понятно как реализовать визуализацию разной разметки элементов. Мы же рассмотрим, как использовать ListView с различными типами элементов, и каким должен быть адаптер данных, который играет в этом важную роль.

Интерфейс элементов

Сначала нужно создать интерфейс, который будут реализовать классы разных элементов. Этот позволят обращаться к элементам одинаково и хранить их в одном списке или массиве. В тоже время классы будут реализовать его по-разному в соответствии с данными. Пример интерфейса:

Item.java
public interface Item {
    public int getViewType();
    public View getView(LayoutInflater inflater, int position, View convertView);
    public long getId();
    public boolean isEnable();
}

Метод getViewType() возвращает тип элемента, getView() создает и возвращает View элемента, метод getId() возвращает идентификатор и метод isEnable() говорит о том, будет ли элемент списка активным, если вернуть false, то на элемент нельзя будет нажать и соответственно не будет события нажатия.

Реализация интерфейса

Для каждого типа элемента нужно создать класс и реализовать интерфейс. При этом класс отвечает за разметку, представление, поведение и хранение соответствующих данных, тем сам мы избавляемся от анализа типа при визуализации и множества других условий. Ниже приведены класс с реализацией нашего интерфейса:

HeaderItem.java
public class HeaderItem implements Item {
    HeaderData item;

    public HeaderItem(HeaderData item) {
        this.item = item;
    }

    @Override
    public int getViewType() {
        return RowType.HEADER_ITEM.ordinal();
    }

    @Override
    public View getView(LayoutInflater inflater, int position, View convertView) {
        // создаем View с определенной разметкой и атрибутами
        // Возвращаем View элемента заголовка
        return convertView;
    }

    @Override
    public long getId() {
        return 0;
    }

    @Override
    public boolean isEnable() {  
        return false;
    }
}
TextItem.java
public class TextItem implements Item {

    private TextData item;

    public TextItem(TextData item) {
        this.item= item;
    }

    @Override
    public int getViewType() {
        return RowType.TEXT_ITEM.ordinal();
    }

    @Override
    public View getView(LayoutInflater inflater, int position, View convertView) {
        // Создаем View с определенной разметкой и атрибутами
        // Возвращаем View обычного элемента
        return convertView;
    }

    @Override
    public long getId() {
        return mItem.programItem.get_id();
    }

    @Override
    public boolean isEnable() {
        return true;
    }

}

Адаптер

В качестве адаптера лучше использовать ArrayAdapter или BaseAdapter, которые обладают двумя очень важными методами. Первый метод getItemViewType(), который возвращает тип элемента в будущем созданного в getView(int, View, ViewGroup) методе. Второй метод getViewTypeCount(), возвращает количество типов элементов в будущем созданных в getView(int, View, ViewGroup) методе. Для определения типов можно использовать Enum и для количества типов метод values() совместно со свойством length. Адаптер выглядит следующим образом:

ListItemsAdapter.java
public class ListItemsAdapter extends ArrayAdapter<Item> {
    protected static LayoutInflater mInflater;

    public enum RowType {
        HEADER_ITEM, TEXT_ITEM
    }

    public ListItemsAdapter(Context context, List<Item> items) {
        super(context, 0, items);
        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public int getViewTypeCount() {
        return RowType.values().length;
    }

    @Override
    public int getItemViewType(int position) {
        return getItem(position).getViewType();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return getItem(position).getView(mInflater, position, convertView);
    }

    @Override
    public long getItemId(int position) {
        return getItem(position).getId();
    }

    @Override
    public boolean isEnabled(int position) {
        return getItem(position).isEnable();
    }
}

Комментариев нет:

Отправить комментарий