Android ListView с различными макетами для каждой строки

android listview listviewitem

192600 просмотра

6 ответа

Я пытаюсь определить лучший способ иметь один ListView, который содержит разные макеты для каждой строки. Я знаю, как создать настраиваемый адаптер строки + настраиваемый массив для поддержки настраиваемой строки для всего представления списка, но как я могу реализовать много разных стилей строк в ListView?

Автор: w.donahue Источник Размещён: 12.11.2019 09:22

Ответы (6)


409 плюса

Решение

Поскольку вы знаете, сколько типов макетов у вас будет - эти методы можно использовать.

getViewTypeCount() - этот метод возвращает информацию о количестве типов строк в вашем списке

getItemViewType(int position) - возвращает информацию, какой тип макета вы должны использовать на основе позиции

Тогда вы раздуть макет только если это нуль и определить тип использования getItemViewType.

Посмотрите на этот учебник для получения дополнительной информации.

Чтобы добиться некоторой оптимизации структуры, которую вы описали в комментарии, я бы предложил:

  • Хранение просмотров в объекте называется ViewHolder. Это увеличит скорость, потому что вам не придется findViewById()каждый раз вызывать getViewметод. Смотрите List14 в демоверсиях API .
  • Создайте один общий макет, который будет соответствовать всем комбинациям свойств и скрыть некоторые элементы, если в текущей позиции его нет.

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

Автор: Cristian Размещён: 23.01.2011 11:33

62 плюса

Я знаю, как создать настраиваемый адаптер строки + настраиваемый массив для поддержки настраиваемой строки для всего представления списка. Но как один просмотр списка может поддерживать много разных стилей строк?

Вы уже знаете основы. Вам просто нужно, чтобы ваш пользовательский адаптер возвращал другой макет / представление на основе предоставленной информации о строке / курсоре.

A ListViewможет поддерживать несколько стилей строк, потому что он является производным от AdapterView :

AdapterView - это представление, чьи дочерние элементы определяются адаптером.

Если вы посмотрите на Адаптер , вы увидите методы, которые учитывают использование специфических для строки представлений:

abstract int getViewTypeCount()
// Returns the number of types of Views that will be created ...

abstract int getItemViewType(int position)
// Get the type of View that will be created ...

abstract View getView(int position, View convertView, ViewGroup parent)
// Get a View that displays the data ...

Последние два метода предоставляют позицию, чтобы вы могли использовать ее для определения типа представления, которое вы должны использовать для этой строки .


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

Например, чтобы использовать ArrayAdapter ,

  • переопределить, getView()чтобы надуть, заполнить и вернуть желаемый вид для данной позиции. getView()Метод включает в себя возможность повторного использования взглядов через convertViewпараметр.

Но использовать производные CursorAdapter ,

  • переопределить, newView()чтобы накачать, заполнить и вернуть желаемый вид для текущего состояния курсора (то есть текущей «строки») [вам также нужно переопределить, bindViewчтобы виджет мог повторно использовать представления]

Тем не менее, чтобы использовать SimpleCursorAdapter ,

  • Определите SimpleCursorAdapter.ViewBinderс помощью setViewValue()метода для раздувания, заполнения и возврата нужного представления для данной строки (текущего состояния курсора) и «столбца» данных. Метод может определять только «специальные» представления и использовать стандартное поведение SimpleCursorAdapter для «нормальных» привязок.

Посмотрите конкретные примеры / учебные пособия для типа адаптера, который вы в конечном итоге используете.

Автор: Bert F Размещён: 24.01.2011 02:24

42 плюса

Посмотрите на код ниже.

Сначала мы создаем пользовательские макеты. В этом случае четыре типа.

even.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="#ff500000"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/text"
        android:textColor="@android:color/white"
        android:layout_width="match_parent"
        android:layout_gravity="center"
        android:textSize="24sp"
        android:layout_height="wrap_content" />

 </LinearLayout>

odd.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="#ff001f50"
    android:gravity="right"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/text"
        android:textColor="@android:color/white"
        android:layout_width="wrap_content"
        android:layout_gravity="center"
        android:textSize="28sp"
        android:layout_height="wrap_content"  />

 </LinearLayout>

white.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="#ffffffff"
    android:gravity="right"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/text"
        android:textColor="@android:color/black"
        android:layout_width="wrap_content"
        android:layout_gravity="center"
        android:textSize="28sp"
        android:layout_height="wrap_content"   />

 </LinearLayout>

black.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="#ff000000"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/text"
        android:textColor="@android:color/white"
        android:layout_width="wrap_content"
        android:layout_gravity="center"
        android:textSize="33sp"
        android:layout_height="wrap_content"   />

 </LinearLayout>

Затем мы создаем элемент списка. В нашем случае со строкой и типом.

public class ListViewItem {
        private String text;
        private int type;

        public ListViewItem(String text, int type) {
            this.text = text;
            this.type = type;
        }

        public String getText() {
            return text;
        }

        public void setText(String text) {
            this.text = text;
        }

        public int getType() {
            return type;
        }

        public void setType(int type) {
            this.type = type;
        }

    }

После этого мы создаем видодержатель. Настоятельно рекомендуется, поскольку ОС Android сохраняет ссылку на макет для повторного использования вашего элемента, когда он исчезает и снова появляется на экране. Если вы не используете этот подход, каждый раз, когда ваш элемент появляется на экране, ОС Android будет создавать новый, вызывая утечку памяти в вашем приложении.

public class ViewHolder {
        TextView text;

        public ViewHolder(TextView text) {
            this.text = text;
        }

        public TextView getText() {
            return text;
        }

        public void setText(TextView text) {
            this.text = text;
        }

    }

Наконец, мы создаем наш собственный адаптер, переопределяющий getViewTypeCount () и getItemViewType (int position).

public class CustomAdapter extends ArrayAdapter {

        public static final int TYPE_ODD = 0;
        public static final int TYPE_EVEN = 1;
        public static final int TYPE_WHITE = 2;
        public static final int TYPE_BLACK = 3;

        private ListViewItem[] objects;

        @Override
        public int getViewTypeCount() {
            return 4;
        }

        @Override
        public int getItemViewType(int position) {
            return objects[position].getType();
        }

        public CustomAdapter(Context context, int resource, ListViewItem[] objects) {
            super(context, resource, objects);
            this.objects = objects;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            ViewHolder viewHolder = null;
            ListViewItem listViewItem = objects[position];
            int listViewItemType = getItemViewType(position);


            if (convertView == null) {

                if (listViewItemType == TYPE_EVEN) {
                    convertView = LayoutInflater.from(getContext()).inflate(R.layout.type_even, null);
                } else if (listViewItemType == TYPE_ODD) {
                    convertView = LayoutInflater.from(getContext()).inflate(R.layout.type_odd, null);
                } else if (listViewItemType == TYPE_WHITE) {
                    convertView = LayoutInflater.from(getContext()).inflate(R.layout.type_white, null);
                } else {
                    convertView = LayoutInflater.from(getContext()).inflate(R.layout.type_black, null);
                }

                TextView textView = (TextView) convertView.findViewById(R.id.text);
                viewHolder = new ViewHolder(textView);

                convertView.setTag(viewHolder);

            } else {
                viewHolder = (ViewHolder) convertView.getTag();
            }

            viewHolder.getText().setText(listViewItem.getText());

            return convertView;
        }

    }

И наша деятельность примерно такая:

private ListView listView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main); // here, you can create a single layout with a listview

        listView = (ListView) findViewById(R.id.listview);

        final ListViewItem[] items = new ListViewItem[40];

        for (int i = 0; i < items.length; i++) {
            if (i == 4) {
                items[i] = new ListViewItem("White " + i, CustomAdapter.TYPE_WHITE);
            } else if (i == 9) {
                items[i] = new ListViewItem("Black " + i, CustomAdapter.TYPE_BLACK);
            } else if (i % 2 == 0) {
                items[i] = new ListViewItem("EVEN " + i, CustomAdapter.TYPE_EVEN);
            } else {
                items[i] = new ListViewItem("ODD " + i, CustomAdapter.TYPE_ODD);
            }
        }

        CustomAdapter customAdapter = new CustomAdapter(this, R.id.text, items);
        listView.setAdapter(customAdapter);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView adapterView, View view, int i, long l) {
                Toast.makeText(getBaseContext(), items[i].getText(), Toast.LENGTH_SHORT).show();
            }
        });

    }
}

Теперь создайте просмотр списка внутри mainactivity.xml, как это

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.example.shivnandan.gygy.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

    <ListView
        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:id="@+id/listView"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"


        android:layout_marginTop="100dp" />

</android.support.design.widget.CoordinatorLayout>
Автор: shiv Размещён: 20.04.2016 09:09

14 плюса

В своем адаптере массива вы переопределяете метод getView (), как вы, вероятно, знакомы с ним. Затем все, что вам нужно сделать, это использовать оператор switch или оператор if, чтобы вернуть определенный пользовательский View в зависимости от аргумента позиции, переданного в метод getView. Android умен в том, что он даст вам convertView только соответствующего типа для вашей позиции / строки; Вам не нужно проверять, что это правильный тип. В этом вы можете помочь Android, переопределив методы getItemViewType () и getViewTypeCount () соответствующим образом.

Автор: Jems Размещён: 23.01.2011 11:32

4 плюса

Если нам нужно отобразить другой тип представления в виде списка, то лучше использовать getViewTypeCount () и getItemViewType () в адаптере вместо переключения представления VIEW.GONE и VIEW.VISIBLE могут быть очень дорогой задачей внутри getView (), которая будет влияет на прокрутку списка.

Пожалуйста, отметьте это для использования getViewTypeCount () и getItemViewType () в адаптере.

Ссылка: the-use-of-getviewtypecount

Автор: kyogs Размещён: 30.06.2014 05:37

1 плюс

ListView был предназначен для простых случаев использования, таких как статический вид для всех элементов строки.
Поскольку вам необходимо создавать ViewHolders, активно использовать getItemViewType()и динамически отображать различные XML-макеты элементов строк, попробуйте сделать это с помощью RecyclerView , который доступен в Android API 22. Он обеспечивает лучшую поддержку и структуру для нескольких типов представлений.

Прочтите это руководство о том, как использовать RecyclerView для того, что вы ищете.

Автор: Phileo99 Размещён: 25.08.2015 05:22
Вопросы из категории :
32x32