ListView насправді вже здатний вимірювати себе досить високим для відображення всіх елементів, але це не робиться, коли ви просто вкажете wrap_content (MeasureSpec.UNSPECIFIED). Це зробить це, коли йому зададуть висоту з MeasureSpec.AT_MOST. Маючи ці знання, ви можете створити дуже простий підклас для вирішення цієї проблеми, який працює набагато краще, ніж будь-яке рішення, розміщене вище. Ви все одно повинні використовувати wrap_content з цим підкласом.
public class ListViewForEmbeddingInScrollView extends ListView {
public ListViewForEmbeddingInScrollView(Context context) {
super(context);
}
public ListViewForEmbeddingInScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ListViewForEmbeddingInScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 4, MeasureSpec.AT_MOST));
}
}
Маніпулювання висотоюMeasureSpec AT_MOST з дуже великим розміром (Integer.MAX_VALUE >> 4) змушує ListView вимірювати всіх своїх дітей до заданої (дуже великої) висоти і встановлювати її висоту відповідно.
Це працює краще, ніж інші рішення з кількох причин:
- Все правильно вимірює (прокладки, роздільники)
- Він вимірює ListView під час проходження міри
- Завдяки №2, він обробляє зміни ширини або кількості елементів правильно, без додаткового коду
Зі зворотного боку, ви можете стверджувати, що робити це покладається на незадокументовану поведінку в SDK, яка може змінитися. З іншого боку, ви можете стверджувати, що саме так wrap_content дійсно повинен працювати з ListView і що поточна поведінка wrap_content просто порушена.
Якщо ви переживаєте, що поведінка може змінитися в майбутньому, вам слід просто скопіювати функцію onMeasure та пов’язані з неї функції з ListView.java та у свій підклас, а потім зробити шлях AT_MOST через onMeasure для запуску UNSPECIFIED.
До речі, я вважаю, що це цілком коректний підхід, коли ви працюєте з невеликою кількістю елементів списку. Це може бути неефективним у порівнянні з LinearLayout, але коли кількість елементів невелика, використання LinearLayout є непотрібною оптимізацією і, отже, зайвою складністю.