Android ListView с различными макетами для каждой строки
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:3362 плюса
Я знаю, как создать настраиваемый адаптер строки + настраиваемый массив для поддержки настраиваемой строки для всего представления списка. Но как один просмотр списка может поддерживать много разных стилей строк?
Вы уже знаете основы. Вам просто нужно, чтобы ваш пользовательский адаптер возвращал другой макет / представление на основе предоставленной информации о строке / курсоре.
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:2442 плюса
Посмотрите на код ниже.
Сначала мы создаем пользовательские макеты. В этом случае четыре типа.
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:324 плюса
Если нам нужно отобразить другой тип представления в виде списка, то лучше использовать getViewTypeCount () и getItemViewType () в адаптере вместо переключения представления VIEW.GONE и VIEW.VISIBLE могут быть очень дорогой задачей внутри getView (), которая будет влияет на прокрутку списка.
Пожалуйста, отметьте это для использования getViewTypeCount () и getItemViewType () в адаптере.
Ссылка: the-use-of-getviewtypecount
Автор: kyogs Размещён: 30.06.2014 05:371 плюс
ListView был предназначен для простых случаев использования, таких как статический вид для всех элементов строки.
Поскольку вам необходимо создавать ViewHolders, активно использовать getItemViewType()
и динамически отображать различные XML-макеты элементов строк, попробуйте сделать это с помощью RecyclerView , который доступен в Android API 22. Он обеспечивает лучшую поддержку и структуру для нескольких типов представлений.
Прочтите это руководство о том, как использовать RecyclerView для того, что вы ищете.
Автор: Phileo99 Размещён: 25.08.2015 05:22Вопросы из категории :
- android Насколько хорошо отражает эмулятор Android Phone?
- android Как сохранить состояние активности Android с помощью сохранения состояния экземпляра?
- android Android: доступ к дочерним представлениям из ListView
- android Как вызвать SOAP веб-сервис на Android
- android Как вы форматируете дату и время в Android?
- android Android: Получение имени файла с камеры?
- listview Как я могу получить доступ к ListViewItems WPF ListView?
- listview Прокрутите список в WPF в определенную строку
- listview c # мерцание Listview при обновлении
- listview Добавление кнопки в ListView в WinForms
- listview Связывание ListView с свойством «IsSelected» ListViewItem
- listview Ленивая загрузка изображений в ListView
- listviewitem Как я могу установить значок для ListViewSubItem?
- listviewitem Android ListView с различными макетами для каждой строки
- listviewitem Как я могу получить пунктирную или пунктирную границу в WPF?
- listviewitem Получить единый список View SelectedItem
- listviewitem Скрытие ListViewItem вместо его удаления?
- listviewitem Android-автообновление элементов списка просмотра