我有一个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个,我可以滚动评论所在的一小部分。我想要一个全局页面滚动


当前回答

It is not possible to use Scroll-view inside List-view as List-view already has scrolling property. To use list-view inside Scroll-view you can follow these steps which worked for me : 1) Create NonScrollListView java file that disable the default scrolling property of list-view. and code is below package your-package-structure; import android.content.Context; import android.util.AttributeSet; import android.view.ViewGroup; import android.widget.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(); } } 2) Now create xml file which which has NestedScrollView and inside this use NonScrollListView for listing your items. This will make your entire screen to scroll with all the views. <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical"> <ViewFlipper android:id="@+id/v_flipper" android:layout_width="match_parent" android:layout_height="130dp"> </ViewFlipper> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="SHOP" android:textSize="15dp" android:textStyle="bold" android:gravity="center" android:padding="5dp" android:layout_marginTop="15dp" android:layout_marginBottom="5dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp"/> <View android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginBottom="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:background="#ddd"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:layout_weight="1" > <com.abc.xyz.NonScrollListView android:id="@+id/listview" android:divider="@null" android:layout_width="match_parent" android:layout_marginBottom="10dp" android:layout_height="match_parent" android:padding="8dp"> </com.abc.xyz.NonScrollListView> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="bottom"> <include layout="@layout/footer" /> </LinearLayout> </LinearLayout> 3) Now in java class i.e, home.java define NonScrollListView instead of Listview. package comabc.xyz.landscapeapp; import android.content.Intent; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.os.Bundle; import android.support.v4.app.FragmentTransaction; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.Button; import android.widget.ImageView; import android.widget.ListView; import android.widget.Toast; import android.widget.Toolbar; import android.widget.ViewFlipper; public class home extends Fragment { int pos = 0; ViewFlipper v_flipper; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.activity_home, container, false); return view; } @Override public void onViewCreated(@NonNull final View view, @Nullable Bundle savedInstanceState) { NonScrollListView listView = (NonScrollListView) view.findViewById(R.id.listview); customAdapter customAdapter = new customAdapter(getActivity()); listView.setAdapter(customAdapter); listView.setFocusable(false); customAdapter.notifyDataSetChanged(); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Log.d("listview click", "onItemClick: "); /* FragmentTransaction fr = getFragmentManager().beginTransaction().replace(R.id.fragment_container, new productdisplay()); fr.putExtra("Position", position); fr.addToBackStack("tag"); fr.commit();*/ Intent intent = new Intent(getActivity(), productdisplay.class); intent.putExtra("Position", position); startActivity(intent); } }); //image slider int images[] = {R.drawable.slide1, R.drawable.slide2, R.drawable.slide3}; v_flipper = view.findViewById(R.id.v_flipper); for (int image : images) { flipperImages(image); } } private void flipperImages(int image) { ImageView imageView = new ImageView(getActivity()); imageView.setBackgroundResource(image); v_flipper.addView(imageView); v_flipper.setFlipInterval(4000); v_flipper.setAutoStart(true); v_flipper.setInAnimation(getActivity(), android.R.anim.slide_in_left); v_flipper.setOutAnimation(getActivity(), android.R.anim.slide_out_right); } } Note: I used Fragments here.

其他回答

千万不要把ListView放在ScrollView里面!你可以在谷歌上找到关于这个主题的更多信息。在你的例子中,使用LinearLayout代替ListView并以编程方式添加元素。

如果出于某种原因你不想使用addHeaderView和addFooterView,例如当你有几个列表时,一个好主意是重用ListAdapter来填充一个简单的线性布局,这样就没有滚动功能了。

如果你已经从ListFragment中获得了一个完整的片段,并且想用简单的线性布局将其转换为一个类似的片段,而不需要滚动(例如,将它放在ScrollView中),你可以像这样实现一个适配器片段:

// converts listFragment to linearLayout (no scrolling)
// please call init() after fragment is inflated to set listFragment to convert
public class ListAsArrayFragment extends Fragment {
    public ListAsArrayFragment() {}

    private ListFragment mListFragment;
    private LinearLayout mRootView;


    // please call me!
    public void init(Activity activity, ListFragment listFragment){
        mListFragment = listFragment;
        mListFragment.onAttach(activity);
        mListFragment.getListAdapter().registerDataSetObserver(new DataSetObserver() {
            @Override
            public void onChanged() {
                super.onChanged();
                refreshView();
            }
        });
    }


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // create an empty vertical LinearLayout as the root view of this fragment
        mRootView = new LinearLayout(getActivity());
        mRootView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        mRootView.setOrientation(LinearLayout.VERTICAL);
        return mRootView;
    }

    // reusing views for performance
    // todo: support for more than one view type
    ArrayList<View> mViewsToReuse = new ArrayList<>();
    ArrayList<View> mCurrentViews = new ArrayList<>();

    // re-add views to linearLayout
    void refreshView(){

        // remove old views from linearLayout and move them to mViewsToReuse
        mRootView.removeAllViews();
        mViewsToReuse.addAll(mCurrentViews);
        mCurrentViews.clear();

        // create new views
        for(int i=0; i<mListFragment.getListAdapter().getCount(); ++i){
            View viewToReuse = null;
            if(!mViewsToReuse.isEmpty()){
                viewToReuse = mViewsToReuse.get(mViewsToReuse.size()-1);
                mViewsToReuse.remove(mViewsToReuse.size()-1);
            }
            final View view = mListFragment.getListAdapter().getView(i, viewToReuse, mRootView);
            ViewGroup.LayoutParams oldParams = view.getLayoutParams();
            view.setLayoutParams(new LinearLayout.LayoutParams(oldParams.width, oldParams.height));
            final int finalI = i;

            // pass click events to listFragment
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mListFragment.onListItemClick(null, view, finalI, finalI);
                }
            });
            mRootView.addView(view);
            mCurrentViews.add(view);
        }
    }

你也可以根据你的需要转发onCreate, onPause, onResume等到原始片段或尝试继承而不是组合(但覆盖某些方法,因此原始片段实际上没有附加到布局层次结构);但是我想尽可能地分离原始片段,因为我们只需要提取它的ListAdapter。如果你在onAttach中调用原始片段的setListAdapter,这可能就足够了。

下面是如何使用ListAsArrayFragment包含OriginalListFragment而不滚动。在父活动的onCreate中:

ListAsArrayFragment fragment = (ListAsArrayFragment) getFragmentManager().findFragmentById(R.id.someFragmentId);
OriginalListFragment originalFragment = new OriginalListFragment();
fragment.init(this, originalFragment);

// now access originalFragment.getListAdapter() to modify list entries
// and remember to call notifyDatasetChanged()

在xml:

<com.example.util.NestedListView
                    android:layout_marginTop="10dp"
                    android:id="@+id/listview"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:divider="@null"

                    android:layout_below="@+id/rl_delivery_type" >
                </com.example.util.NestedListView>

在Java中:

public class NestedListView extends ListView implements View.OnTouchListener, AbsListView.OnScrollListener {

    private int listViewTouchAction;
    private static final int MAXIMUM_LIST_ITEMS_VIEWABLE = 99;

    public NestedListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        listViewTouchAction = -1;
        setOnScrollListener(this);
        setOnTouchListener(this);
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
                         int visibleItemCount, int totalItemCount) {
        if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
            if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
                scrollBy(0, -1);
            }
        }
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int newHeight = 0;
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        if (heightMode != MeasureSpec.EXACTLY) {
            ListAdapter listAdapter = getAdapter();
            if (listAdapter != null && !listAdapter.isEmpty()) {
                int listPosition = 0;
                for (listPosition = 0; listPosition < listAdapter.getCount()
                        && listPosition < MAXIMUM_LIST_ITEMS_VIEWABLE; listPosition++) {
                    View listItem = listAdapter.getView(listPosition, null, this);
                    //now it will not throw a NPE if listItem is a ViewGroup instance
                    if (listItem instanceof ViewGroup) {
                        listItem.setLayoutParams(new LayoutParams(
                                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
                    }
                    listItem.measure(widthMeasureSpec, heightMeasureSpec);
                    newHeight += listItem.getMeasuredHeight();
                }
                newHeight += getDividerHeight() * listPosition;
            }
            if ((heightMode == MeasureSpec.AT_MOST) && (newHeight > heightSize)) {
                if (newHeight > heightSize) {
                    newHeight = heightSize;
                }
            }
        } else {
            newHeight = getMeasuredHeight();
        }
        setMeasuredDimension(getMeasuredWidth(), newHeight);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
            if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
                scrollBy(0, 1);
            }
        }
        return false;
    }
}

我有一个类似于原始海报的问题——如何让列表视图在滚动视图中滚动——这个答案解决了我的问题。 禁止滚动包含在ScrollView中的ListView

我没有调用新的片段到现有的布局或类似的东西,就像OP所做的那样,所以我的代码看起来像这样:

<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" >


    <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/my_listView"
       android:layout_width="match_parent"
       android:layout_height="wrap_content">
   </ListView>

</LinearLayout>

</ScrollView>

基本上我要做的是在我调用它之前检查listview的长度,当我调用它时,我把它变成那个长度。在你的java类中使用这个函数:

public static void justifyListViewHeightBasedOnChildren (ListView listView) {

    ListAdapter adapter = listView.getAdapter();

    if (adapter == null) {
        return;
    }
    ViewGroup vg = listView;
    int totalHeight = 0;
    for (int i = 0; i < adapter.getCount(); i++) {
        View listItem = adapter.getView(i, null, vg);
        listItem.measure(0, 0);
        totalHeight += listItem.getMeasuredHeight();
    }

    ViewGroup.LayoutParams par = listView.getLayoutParams();
    par.height = totalHeight + (listView.getDividerHeight() * (adapter.getCount() - 1));
    listView.setLayoutParams(par);
    listView.requestLayout();
}

然后像这样调用函数:

justifyListViewHeightBasedOnChildren(listView);

结果是一个没有滚动条的列表视图,显示整个列表视图的长度,它与滚动视图的滚动条一起滚动。

我知道已经很长时间了,但我也有这个问题,尝试了这个解决方案,它是有效的。所以我想这对其他人也有帮助。

我添加android:fillViewport="true"的布局xml为scrollView。 总的来说,ScrollView是这样的。

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/scrollView6" 
    android:fillViewport="true">

这对我来说就像魔法一样。 位于ScrollView内部的ListView再次扩展到它的大小。

下面是ScrollView和ListView的完整示例代码。

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/scrollView6" android:fillViewport="true">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        ....
        <ListView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/lv_transList" android:layout_gravity="top"
            android:layout_marginTop="5dp"/>
        ....
    </LinearLayout>
</ScrollView>