我到处寻找这个问题的解决方案,我能找到的唯一答案似乎是“不要把一个ListView放入一个ScrollView”。不过,我还没有看到任何真正的解释。我能找到的唯一原因似乎是谷歌认为你不应该这么做。我知道,所以我做了。
问题是,如何将ListView放到ScrollView中而不缩到最小高度?
我到处寻找这个问题的解决方案,我能找到的唯一答案似乎是“不要把一个ListView放入一个ScrollView”。不过,我还没有看到任何真正的解释。我能找到的唯一原因似乎是谷歌认为你不应该这么做。我知道,所以我做了。
问题是,如何将ListView放到ScrollView中而不缩到最小高度?
当前回答
这是DougW、Good Guy Greg和Paul的答案组合。我发现当尝试使用自定义列表视图适配器和非标准列表项时,这都是需要的,否则列表视图会导致应用程序崩溃(也会导致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);
}
其他回答
你不应该把ListView放到ScrollView中因为ListView已经是一个ScrollView了。这就像把一个ScrollView放到一个ScrollView中。
你想要完成什么?
如果LinearLayout有一个setAdapter方法,整个问题就会消失,因为当你告诉别人使用它时,替代方案将是微不足道的。
如果你想要一个滚动的ListView在另一个滚动视图中,这不会有帮助,但至少会给你一个想法。
您需要创建一个自定义适配器来组合要滚动的所有内容,并将ListView的适配器设置为该内容。
我手头没有样本代码,但如果你想要。
<ListView/>
(other content)
<ListView/>
然后需要创建一个表示所有这些内容的适配器。ListView/Adapters也足够智能,可以处理不同的类型,但是您需要自己编写适配器。
android的UI API并不像其他平台那么成熟,所以它不像其他平台那么精致。此外,当你在android上做一些事情时,你需要以android (unix)的心态来做任何事情,你可能不得不将更小的部分的功能组装起来,并编写一堆自己的代码来让它工作。
虽然建议的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);
}
}
}
}
这是唯一对我有效的方法:
你可以在棒棒糖上使用
yourtListView.setNestedScrollingEnabled(true);
这将启用或禁用此视图的嵌套滚动 如果你需要向后兼容旧版本的操作系统,你必须使用RecyclerView。
在ScrollView中使用ListView有两个问题。
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);
}
}
这是我发现的最好的方法!