Ответ 1
Использование ListView
, чтобы сделать его не прокруткой, чрезвычайно дорого и противоречит целям ListView
. Вы должны НЕ сделать это. Просто используйте LinearLayout
вместо этого.
Я искал решения для этой проблемы, и единственный ответ, который я могу найти, кажется " не помещает ListView в ScrollView". Мне еще предстоит увидеть какое-то реальное объяснение, почему. Единственная причина, по которой я могу найти, - это то, что Google не думает, что вам следует это делать. Ну, я так и сделал.
Итак, вопрос в том, как вы можете разместить ListView в ScrollView без его свертывания до минимальной высоты?
Использование ListView
, чтобы сделать его не прокруткой, чрезвычайно дорого и противоречит целям ListView
. Вы должны НЕ сделать это. Просто используйте LinearLayout
вместо этого.
Вот мое решение. Я новичок в платформе Android, и я уверен, что это немного хаки, особенно в том, что касается прямого вызова .measure и установки свойства LayoutParams.height
, но он работает.
Все, что вам нужно сделать, это позвонить Utility.setListViewHeightBasedOnChildren(yourListView)
, и он будет изменен, чтобы точно соответствовать высоте его элементов.
public class Utility {
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom();
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
if (listItem instanceof ViewGroup) {
listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
}
Это определенно будет работать............
Вы должны просто заменить свой <ScrollView ></ScrollView>
в XML файле макета таким Custom ScrollView
как <com.tmd.utils.VerticalScrollview > </com.tmd.utils.VerticalScrollview >
package com.tmd.utils;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ScrollView;
public class VerticalScrollview extends ScrollView{
public VerticalScrollview(Context context) {
super(context);
}
public VerticalScrollview(Context context, AttributeSet attrs) {
super(context, attrs);
}
public VerticalScrollview(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action)
{
case MotionEvent.ACTION_DOWN:
Log.i("VerticalScrollview", "onInterceptTouchEvent: DOWN super false" );
super.onTouchEvent(ev);
break;
case MotionEvent.ACTION_MOVE:
return false; // redirect MotionEvents to ourself
case MotionEvent.ACTION_CANCEL:
Log.i("VerticalScrollview", "onInterceptTouchEvent: CANCEL super false" );
super.onTouchEvent(ev);
break;
case MotionEvent.ACTION_UP:
Log.i("VerticalScrollview", "onInterceptTouchEvent: UP super false" );
return false;
default: Log.i("VerticalScrollview", "onInterceptTouchEvent: " + action ); break;
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
super.onTouchEvent(ev);
Log.i("VerticalScrollview", "onTouchEvent. action: " + ev.getAction() );
return true;
}
}
При вводе ListView
внутри ScrollView
мы можем использовать ListView
как ScrollView
. Вещи, которые должны быть в ListView
, могут быть помещены внутри ListView
. Другие макеты сверху и снизу ListView
можно добавить, добавив макеты в верхний и нижний колонтитулы ListView
. Таким образом, весь ListView
даст вам опыт прокрутки.
Есть много ситуаций, когда имеет смысл иметь ListView в ScrollView.
Здесь код, основанный на предложении DougW... работает в фрагменте, занимает меньше памяти.
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}
int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
int totalHeight = 0;
View view = null;
for (int i = 0; i < listAdapter.getCount(); i++) {
view = listAdapter.getView(i, view, listView);
if (i == 0) {
view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, LayoutParams.WRAP_CONTENT));
}
view.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
totalHeight += view.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
вызовите setListViewHeightBasedOnChildren (listview) для каждого встроенного списка.
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));
}
}
Манипулирование heightMeasureSpec как AT_MOST с очень большим размером (Integer.MAX_VALUE → 4) заставляет ListView измерять все его дочерние элементы до заданной (очень большой) высоты и соответственно устанавливать ее высоту.
Это работает лучше, чем другие решения по нескольким причинам:
С другой стороны, вы можете утверждать, что это связано с недокументированным поведением в SDK, которое может измениться. С другой стороны, вы можете утверждать, что именно так должно работать wrap_content с ListView и что текущее поведение wrap_content просто сломано.
Если вы опасаетесь, что поведение может измениться в будущем, вы должны просто скопировать функцию onMeasure и связанные с ней функции из списка ListView.java и в свой собственный подкласс, а затем сделать путь AT_MOST с помощью операции onMeasure для UNSPECIFIED.
Кстати, я считаю, что это очень эффективный подход, когда вы работаете с небольшим количеством элементов списка. Это может быть неэффективно по сравнению с LinearLayout, но когда количество элементов невелико, использование LinearLayout - это ненужная оптимизация и, следовательно, ненужная сложность.
Там есть встроенная настройка. В ScrollView:
android:fillViewport="true"
В Java,
mScrollView.setFillViewport(true);
Ромен Гай подробно объясняет это: http://www.curious-creature.org/2010/08/15/scrollviews-handy-trick/
Мы не могли бы использовать две прокрутки одновременно. Мы получим общую длину ListView и раскройте listview с общей высотой. Затем мы можем добавить ListView в ScrollView напрямую или с помощью LinearLayout, потому что ScrollView имеет непосредственно один ребенок. скопируйте метод setListViewHeightBasedOnChildren (lv) в свой код и разверните listview, после чего вы можете использовать listview внутри scrollview. \ layout xml file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#1D1D1D"
android:orientation="vertical"
android:scrollbars="none" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#1D1D1D"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="40dip"
android:background="#333"
android:gravity="center_vertical"
android:paddingLeft="8dip"
android:text="First ListView"
android:textColor="#C7C7C7"
android:textSize="20sp" />
<ListView
android:id="@+id/first_listview"
android:layout_width="260dp"
android:layout_height="wrap_content"
android:divider="#00000000"
android:listSelector="#ff0000"
android:scrollbars="none" />
<TextView
android:layout_width="fill_parent"
android:layout_height="40dip"
android:background="#333"
android:gravity="center_vertical"
android:paddingLeft="8dip"
android:text="Second ListView"
android:textColor="#C7C7C7"
android:textSize="20sp" />
<ListView
android:id="@+id/secondList"
android:layout_width="260dp"
android:layout_height="wrap_content"
android:divider="#00000000"
android:listSelector="#ffcc00"
android:scrollbars="none" />
</LinearLayout>
</ScrollView>
</LinearLayout>
onCreate метод в классе Activity:
import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.listview_inside_scrollview);
ListView list_first=(ListView) findViewById(R.id.first_listview);
ListView list_second=(ListView) findViewById(R.id.secondList);
ArrayList<String> list=new ArrayList<String>();
for(int x=0;x<30;x++)
{
list.add("Item "+x);
}
ArrayAdapter<String> adapter=new ArrayAdapter<String>(getApplicationContext(),
android.R.layout.simple_list_item_1,list);
list_first.setAdapter(adapter);
setListViewHeightBasedOnChildren(list_first);
list_second.setAdapter(adapter);
setListViewHeightBasedOnChildren(list_second);
}
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight
+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
Создается пользовательский ListView, который не прокручивается
public class NonScrollListView extends ListView {
public NonScrollListView(Context context) {
super(context);
}
public NonScrollListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NonScrollListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
}
В файле ресурсов макета
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<!-- com.Example Changed with your Package name -->
<com.Example.NonScrollListView
android:id="@+id/lv_nonscroll_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</com.Example.NonScrollListView>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/lv_nonscroll_list" >
<!-- Your another layout in scroll view -->
</RelativeLayout>
</RelativeLayout>
В файле Java
Создайте объект customListview вместо ListView, например: NonScrollListView non_scroll_list = (NonScrollListView) findViewById (R.id.lv_nonscroll_list);
Это комбинация ответов Дуга, Доброго Гая Грега и Павла. Я обнаружил, что это было необходимо при попытке использовать это с помощью настраиваемого адаптера listview и нестандартных элементов списка, иначе listview разбил приложение (также разбился с ответом Nex):
public void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}
int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom();
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
if (listItem instanceof ViewGroup)
listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
Я преобразовал @DougW Utility
в С# (используется в Xamarin). Следующее работает отлично для элементов фиксированной высоты в списке и будет в основном прекрасным или, по крайней мере, хорошим началом, если только некоторые из элементов немного больше стандартного элемента.
// You will need to put this Utility class into a code file including various
// libraries, I found that I needed at least System, Linq, Android.Views and
// Android.Widget.
using System;
using System.Linq;
using Android.Views;
using Android.Widget;
namespace UtilityNamespace // whatever you like, obviously!
{
public class Utility
{
public static void setListViewHeightBasedOnChildren (ListView listView)
{
if (listView.Adapter == null) {
// pre-condition
return;
}
int totalHeight = listView.PaddingTop + listView.PaddingBottom;
for (int i = 0; i < listView.Count; i++) {
View listItem = listView.Adapter.GetView (i, null, listView);
if (listItem.GetType () == typeof(ViewGroup)) {
listItem.LayoutParameters = new LinearLayout.LayoutParams (ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
}
listItem.Measure (0, 0);
totalHeight += listItem.MeasuredHeight;
}
listView.LayoutParameters.Height = totalHeight + (listView.DividerHeight * (listView.Count - 1));
}
}
}
Спасибо @DougW, это привело меня в затруднительное положение, когда мне пришлось работать с OtherPeople'Code.: -)
Вы не должны помещать ListView в ScrollView, потому что ListView уже является ScrollView. Таким образом, это будет похоже на создание ScrollView в ScrollView.
Что вы пытаетесь выполнить?
Эй, у меня была аналогичная проблема. Я хотел отобразить представление списка, которое не прокручивалось, и я обнаружил, что манипуляция параметрами работает, но неэффективна и будет вести себя по-разному на разных устройствах. В результате это часть моего кода расписания, которая на самом деле делает это очень эффективно.
db = new dbhelper(this);
cursor = db.dbCursor();
int count = cursor.getCount();
if (count > 0)
{
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.layoutId);
startManagingCursor(YOUR_CURSOR);
YOUR_ADAPTER(**or SimpleCursorAdapter **) adapter = new YOUR_ADAPTER(this,
R.layout.itemLayout, cursor, arrayOrWhatever, R.id.textViewId,
this.getApplication());
int i;
for (i = 0; i < count; i++){
View listItem = adapter.getView(i,null,null);
linearLayout.addView(listItem);
}
}
Примечание. Если вы используете это, notifyDataSetChanged();
не будет работать так, как только просмотры не будут перерисовываться.
Сделайте это, если вам нужна работа вокруг
adapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
super.onChanged();
removeAndRedrawViews();
}
});
Есть две проблемы при использовании ListView внутри ScrollView.
1- ListView должен полностью развернуться до высоты своих детей. этот ListView разрешает это:
public class ListViewExpanded extends ListView
{
public ListViewExpanded(Context context, AttributeSet attrs)
{
super(context, attrs);
setDividerHeight(0);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST));
}
}
Высота разделителя должна быть 0, вместо этого используйте прокладку в строках.
2- ListView потребляет события касания, поэтому ScrollView нельзя прокручивать, как обычно. Этот ScrollView разрешает эту проблему:
public class ScrollViewInterceptor extends ScrollView
{
float startY;
public ScrollViewInterceptor(Context context, AttributeSet attrs)
{
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e)
{
onTouchEvent(e);
if (e.getAction() == MotionEvent.ACTION_DOWN) startY = e.getY();
return (e.getAction() == MotionEvent.ACTION_MOVE) && (Math.abs(startY - e.getY()) > 50);
}
}
Это лучший способ найти трюк!
Это единственное, что сработало для меня:
на Lollipop вперед вы можете использовать
yourtListView.setNestedScrollingEnabled(true);
Включить или отключить вложенную прокрутку для этого представления если вам нужна обратная совместимость со старой версией ОС, вам придется использовать RecyclerView.
благодаря код Vinay здесь мой код, когда вы не можете иметь listview внутри scrollview, но вам нужно что-то вроде этого
LayoutInflater li = LayoutInflater.from(this);
RelativeLayout parent = (RelativeLayout) this.findViewById(R.id.relativeLayoutCliente);
int recent = 0;
for(Contatto contatto : contatti)
{
View inflated_layout = li.inflate(R.layout.header_listview_contatti, layout, false);
inflated_layout.setId(contatto.getId());
((TextView)inflated_layout.findViewById(R.id.textViewDescrizione)).setText(contatto.getDescrizione());
((TextView)inflated_layout.findViewById(R.id.textViewIndirizzo)).setText(contatto.getIndirizzo());
((TextView)inflated_layout.findViewById(R.id.textViewTelefono)).setText(contatto.getTelefono());
((TextView)inflated_layout.findViewById(R.id.textViewMobile)).setText(contatto.getMobile());
((TextView)inflated_layout.findViewById(R.id.textViewFax)).setText(contatto.getFax());
((TextView)inflated_layout.findViewById(R.id.textViewEmail)).setText(contatto.getEmail());
RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
if (recent == 0)
{
relativeParams.addRule(RelativeLayout.BELOW, R.id.headerListViewContatti);
}
else
{
relativeParams.addRule(RelativeLayout.BELOW, recent);
}
recent = inflated_layout.getId();
inflated_layout.setLayoutParams(relativeParams);
//inflated_layout.setLayoutParams( new RelativeLayout.LayoutParams(source));
parent.addView(inflated_layout);
}
relativeLayout остается внутри ScrollView, поэтому он становится прокручиваемым:)
Ниже приведена небольшая модификация @djunod , которая мне нужна, чтобы она работала отлично:
public static void setListViewHeightBasedOnChildren(ListView listView)
{
ListAdapter listAdapter = listView.getAdapter();
if(listAdapter == null) return;
if(listAdapter.getCount() <= 1) return;
int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
int totalHeight = 0;
View view = null;
for(int i = 0; i < listAdapter.getCount(); i++)
{
view = listAdapter.getView(i, view, listView);
view.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
totalHeight += view.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
Хотя предлагаемые методы setListViewHeightBasedOnChildren() работают в большинстве случаев, в некоторых случаях, особенно с большим количеством элементов, я заметил, что последние элементы не отображаются. Поэтому я решил подражать простой версии поведения ListView, чтобы повторно использовать любой код адаптера, вот альтернатива ListView:
import android.content.Context;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
public class StretchedListView extends LinearLayout {
private final DataSetObserver dataSetObserver;
private ListAdapter adapter;
private OnItemClickListener onItemClickListener;
public StretchedListView(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(LinearLayout.VERTICAL);
this.dataSetObserver = new DataSetObserver() {
@Override
public void onChanged() {
syncDataFromAdapter();
super.onChanged();
}
@Override
public void onInvalidated() {
syncDataFromAdapter();
super.onInvalidated();
}
};
}
public void setAdapter(ListAdapter adapter) {
ensureDataSetObserverIsUnregistered();
this.adapter = adapter;
if (this.adapter != null) {
this.adapter.registerDataSetObserver(dataSetObserver);
}
syncDataFromAdapter();
}
protected void ensureDataSetObserverIsUnregistered() {
if (this.adapter != null) {
this.adapter.unregisterDataSetObserver(dataSetObserver);
}
}
public Object getItemAtPosition(int position) {
return adapter != null ? adapter.getItem(position) : null;
}
public void setSelection(int i) {
getChildAt(i).setSelected(true);
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public ListAdapter getAdapter() {
return adapter;
}
public int getCount() {
return adapter != null ? adapter.getCount() : 0;
}
private void syncDataFromAdapter() {
removeAllViews();
if (adapter != null) {
int count = adapter.getCount();
for (int i = 0; i < count; i++) {
View view = adapter.getView(i, null, this);
boolean enabled = adapter.isEnabled(i);
if (enabled) {
final int position = i;
final long id = adapter.getItemId(position);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(null, v, position, id);
}
}
});
}
addView(view);
}
}
}
}
попробуйте это, это работает для меня, я забыл, где я его нашел, где-то в переполнении стека, Я не здесь, чтобы объяснить это, почему это не работает, но это ответ:).
final ListView AturIsiPulsaDataIsiPulsa = (ListView) findViewById(R.id.listAturIsiPulsaDataIsiPulsa);
AturIsiPulsaDataIsiPulsa.setOnTouchListener(new ListView.OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
int action = event.getAction();
switch (action)
{
case MotionEvent.ACTION_DOWN:
// Disallow ScrollView to intercept touch events.
v.getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_UP:
// Allow ScrollView to intercept touch events.
v.getParent().requestDisallowInterceptTouchEvent(false);
break;
}
// Handle ListView touch events.
v.onTouchEvent(event);
return true;
}
});
AturIsiPulsaDataIsiPulsa.setClickable(true);
AturIsiPulsaDataIsiPulsa.setAdapter(AturIsiPulsaDataIsiPulsaAdapter);
EDIT!, я наконец узнал, где я получил код. Вот!: ListView внутри ScrollView не прокручивается на Android
Решение, которое я использую, заключается в том, чтобы добавить все содержимое ScrollView (что должно быть выше и под listView) как headerView и footerView в ListView.
Таким образом, он работает так же, как и конвертирование, как это должно быть.
Все эти ответы неверны!!! Если вы пытаетесь поместить список в свиток, вы должны пересмотреть свой дизайн. Вы пытаетесь поместить ScrollView в ScrollView. Вмешательство в список повредит производительности списка. Он был спроектирован таким образом, как Android Android.
Если вы действительно хотите, чтобы список находился в том же прокрутке, что и другие элементы, все, что вам нужно сделать, это добавить другие элементы в верхнюю часть списка, используя простой оператор switch в вашем адаптере:
class MyAdapter extends ArrayAdapter{
public MyAdapter(Context context, int resource, List objects) {
super(context, resource, objects);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewItem viewType = getItem(position);
switch(viewType.type){
case TEXTVIEW:
convertView = layouteInflater.inflate(R.layout.textView1, parent, false);
break;
case LISTITEM:
convertView = layouteInflater.inflate(R.layout.listItem, parent, false);
break; }
return convertView;
}
}
Адаптер списка может обрабатывать все, поскольку он отображает только то, что видно.
Раньше это было невозможно. Но с выпуском новых библиотек Appcompat и библиотек Design, это может быть достигнуто.
Вам просто нужно использовать NestedScrollView https://developer.android.com/reference/android/support/v4/widget/NestedScrollView.html
Я не знаю, что он будет работать со списком или нет, но работает с RecyclerView.
Фрагмент кода:
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.v4.widget.NestedScrollView>
Вся эта проблема просто исчезнет, если у LinearLayout был метод setAdapter, потому что тогда, когда вы сказали кому-то использовать его, альтернатива была бы тривиальной.
Если вы действительно хотите прокручивать ListView внутри другого прокрутки, это не поможет, но в противном случае это, по крайней мере, даст вам представление.
Вам нужно создать пользовательский адаптер для объединения всего содержимого, которое вы хотите прокрутить, и установить для него адаптер ListView.
У меня нет примерного кода, но если вы хотите что-то вроде.
<ListView/>
(other content)
<ListView/>
Затем вам нужно создать адаптер, который представляет все это содержимое. ListView/Adapters достаточно умен, чтобы обрабатывать разные типы, но вам нужно написать адаптер самостоятельно.
API интерфейса Android не так зреет, как и все остальное, поэтому он не имеет таких же тонкостей, как другие платформы. Кроме того, когда вы делаете что-то на android, вам нужно быть в Android-симуляции (unix), где вы ожидаете, что что-то, что вам, вероятно, придется собирать для работы с меньшими частями, и написать кучу своего собственного кода, чтобы получить его работа.
Когда мы помещаем ListView
внутри ScrollView
, возникают две проблемы. Один из них ScrollView
измеряет своих детей в режиме UNSPECIFIED, поэтому ListView
устанавливает свою собственную высоту, чтобы разместить только один элемент (я не знаю почему), другой ScrollView
перехватывает событие касания, поэтому ListView
не прокручивает.
Но мы можем разместить ListView
внутри ScrollView
с помощью некоторого обходного пути. Этот пост, я объясняю обходным путем. К этому решению мы также можем сохранить функцию утилизации ListView
.
Вместо того чтобы помещать список в Scrollview, поместите остальную часть содержимого между списком и открытием Scrollview в виде отдельного представления и установите это представление как заголовок списка. Таким образом, вы, наконец, закончите только просмотр списка с учетом прокрутки.
Эта библиотека является самым простым и быстрым решением проблемы.
Вот моя версия кода, которая вычисляет общую высоту списка. Это работает для меня:
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null || listAdapter.getCount() < 2) {
// pre-condition
return;
}
int totalHeight = 0;
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(BCTDApp.getDisplaySize().width, View.MeasureSpec.AT_MOST);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
if (listItem instanceof ViewGroup) listItem.setLayoutParams(lp);
listItem.measure(widthMeasureSpec, heightMeasureSpec);
totalHeight += listItem.getMeasuredHeight();
}
totalHeight += listView.getPaddingTop() + listView.getPaddingBottom();
totalHeight += (listView.getDividerHeight() * (listAdapter.getCount() - 1));
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight;
listView.setLayoutParams(params);
listView.requestLayout();
}