我有一个android布局,其中有一个带有许多元素的scrollView。在scrollView的底部,我有一个listView,然后由适配器填充。

我遇到的问题是,android是排除listView从scrollView作为scrollView已经有一个可滚动的功能。我希望listView和内容一样长,并且主滚动视图是可滚动的。

我怎样才能实现这种行为呢?

这是我的主要布局:

<ScrollView
    android:id="@+id/scrollView1"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="2"
    android:fillViewport="true"
    android:gravity="top" >

    <LinearLayout
        android:id="@+id/foodItemActvity_linearLayout_fragments"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >
    </LinearLayout>

</ScrollView>

然后,我以编程方式将我的组件添加到linearlayour的id: foodItemActvity_linearLayout_fragments。下面是加载到线性布局中的一个视图。就是这个给我的卷轴带来了麻烦。

<?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="wrap_content"
    android:orientation="vertical" >

    <TextView
       android:id="@+id/fragment_dds_review_textView_label"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Reviews:"
       android:textAppearance="?android:attr/textAppearanceMedium" />

   <ListView
       android:id="@+id/fragment_dds_review_listView"
       android:layout_width="match_parent"
       android:layout_height="wrap_content">
   </ListView>
</LinearLayout>

我的适配器然后填充这个列表视图。

当我点击主scrollView时,这是一个来自android层级查看器的图像:

如您所见,它排除了评论列表视图。

我应该能够向下滚动页面,看到8个评论,但它只显示了这3个,我可以滚动评论所在的一小部分。我想要一个全局页面滚动


当前回答

 <ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

       <ListView
           android:id="@+id/listView"
           android:layout_width="match_parent"
           android:layout_height="match_parent"/>

    </LinearLayout>
</ScrollView>

其他回答

如果你想在ScrollView中显示listView中的所有项,请使用这段代码

val params: ViewGroup.LayoutParams = listView!!.layoutParams
params.height = useitemsList.size * 200 //add static height 
listView!!.layoutParams = params
listView!!.requestLayout()

你可以很容易地把ListView放在ScrollView! 只需要通过编程方式改变ListView的高度,就像这样:

    ViewGroup.LayoutParams listViewParams = (ViewGroup.LayoutParams)listView.getLayoutParams();
    listViewParams.height = 400;
    listView.requestLayout();

这是完美的!

最好的解决方案是添加这个android:nestedScrollingEnabled="true"属性在孩子滚动,例如,我已经插入这个属性在我的ListView,是ScrollView的孩子。我希望这个方法对你有用:-

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:gravity="center_horizontal">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="TextView"/>
        <ListView
            android:nestedScrollingEnabled="true" //add this only
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="300dp"/>
    </LinearLayout>
</ScrollView>

正如其他人已经提到的,不要在ScrollView中使用ListView。

为了解决问题,你可以使用LinearLayout,但仍然要保持整洁-用适配器填充你的LinearLayout,就像你用ListView做的一样

您可以使用这个类作为支持适配器的线性布局替代品

import android.content.Context;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;

public class AdaptableLinearLayout extends LinearLayout {

private BaseAdapter mAdapter;

private int mItemCount = 0;

private boolean mDisableChildrenWhenDisabled = false;

private int mWidthMeasureSpec;
private int mHeightMeasureSpec;


public AdaptableLinearLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    // TODO Auto-generated constructor stub
}

public BaseAdapter getAdapter() {
    return mAdapter;
}

public void setAdapter(BaseAdapter adapter) {
    mAdapter = adapter;
    adapter.registerDataSetObserver(new DataSetObserver() {
        @Override
        public void onChanged() {
            updateLayout();
            super.onChanged();
        }

        @Override
        public void onInvalidated() {
            updateLayout();
            super.onInvalidated();
        }
    });
    updateLayout();
}

private void updateLayout() {
    mItemCount = mAdapter.getCount();
    requestLayout();
    invalidate();
}

/**
 * set size for the current View
 */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    mWidthMeasureSpec = widthMeasureSpec;
    mHeightMeasureSpec = heightMeasureSpec;

    removeAllViewsInLayout();
    for (int i = 0; i < mItemCount; i++) {
        makeAndAddView(i);
    }
}

private View makeAndAddView(int position) {
    View child;

    // Nothing found in the recycler -- ask the adapter for a view
    child = mAdapter.getView(position, null, this);

    // Position the view
    setUpChild(child, position);

    return child;

}

private void setUpChild(View child, int position) {

    ViewGroup.LayoutParams lp = child.getLayoutParams();
    if (lp == null) {
        lp = generateDefaultLayoutParams();
    }
    addViewInLayout(child, position, lp);

    // Get measure specs
    int childHeightSpec = ViewGroup.getChildMeasureSpec(mHeightMeasureSpec, getPaddingTop() + getPaddingBottom(), lp.height);
    int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec, getPaddingLeft() + getPaddingRight(), lp.width);

    // Measure child
    child.measure(childWidthSpec, childHeightSpec);

    int childLeft;
    int childRight;

    // Position vertically based on gravity setting
    int childTop = getPaddingTop() + ((getMeasuredHeight() - getPaddingBottom() - getPaddingTop() - child.getMeasuredHeight()) / 2);
    int childBottom = childTop + child.getMeasuredHeight();

    int width = child.getMeasuredWidth();
    childLeft = 0;
    childRight = childLeft + width;

    child.layout(childLeft, childTop, childRight, childBottom);

    if (mDisableChildrenWhenDisabled) {
        child.setEnabled(isEnabled());
    }
}
}

好吧,这是我的答案。固定ListView高度的方法足够封闭,但并不完美。如果大多数项目都是相同的高度,那工作得很好。但如果不是,那就有大问题了。我尝试了很多次,当我输出listItem的值时。getMeasureHeight和listItem。getMeasuerWidth到日志中,我看到宽度值变化很大,这在这里是不期望的,因为同一ListView中的所有项应该具有相同的宽度。问题来了:

有些人使用度量(0,0),这实际上使视图在两个方向上都没有边界,宽度也失控了。有些人尝试获取listView的twidth,但它返回0,没有意义。

当我进一步了解android如何渲染视图时,我意识到所有这些尝试都无法达到我搜索的答案,除非这些函数在视图渲染后运行。

这一次我使用getViewTreeObserver在ListView上,我想固定高度,然后添加ongloballayoutlistener。在这个方法中,我声明了一个新的OnGlobalLayoutListener,在这个方法中,getWidth返回ListView的实际宽度。

private void getLayoutWidth(final ListView lv, final int pad){
        //final ArrayList<Integer> width = new ArrayList<Integer>();

        ViewTreeObserver vto = lv.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                lv.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                //width.add(layout.getMeasuredWidth());
                int width = lv.getMeasuredWidth();
                ListUtils.setDynamicHeight(lv, width, pad);
            }
        });
    }

public static class ListUtils {
        //private static final int UNBOUNDED = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        public static void setDynamicHeight(ListView mListView, int width, int pad) {
            ListAdapter mListAdapter = mListView.getAdapter();
            mListView.getParent();
            if (mListAdapter == null) {
                // when adapter is null
                return;
            }
            int height = 0;


            int desiredWidth = View.MeasureSpec.makeMeasureSpec(width - 2*pad, View.MeasureSpec.EXACTLY);
            for (int i = 0; i < mListAdapter.getCount(); i++) {
                View listItem = mListAdapter.getView(i, null, mListView);

                listItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
                //listItem.measure(UNBOUNDED, UNBOUNDED);
                height += listItem.getMeasuredHeight() + 2*pad;
                Log.v("ViewHeight :", mListAdapter.getClass().toString() + " " + listItem.getMeasuredHeight() + "--" + listItem.getMeasuredWidth());
            }
            ViewGroup.LayoutParams params = mListView.getLayoutParams();
            params.height = height + (mListView.getDividerHeight() * (mListAdapter.getCount() - 1));
            mListView.setLayoutParams(params);
            mListView.requestLayout();
        }
    }

value pad,是我在ListView layout中设置的填充。