Android list view inside a scroll view

后端 未结 30 1928
一向
一向 2020-11-21 13:43

I have an android layout which has a scrollView with a number of elements with in it. At the bottom of the scrollView I have a listView

相关标签:
30条回答
  • 2020-11-21 14:00

    Do NEVER put a ListView inside of a ScrollView! You can find more information about that topic on Google. In your case, use a LinearLayout instead of the ListView and add the elements programmatically.

    0 讨论(0)
  • 2020-11-21 14:00

    found a solution for scrollview -> viewpager -> FragmentPagerAdapter -> fragment -> dynamic listview, but im not the author. there is some bugs, but at least it works

    public class CustomPager extends ViewPager {
    
        private View mCurrentView;
    
        public CustomPager(Context context) {
            super(context);
        }
    
        public CustomPager(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            if (mCurrentView == null) {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
                return;
            }
            int height = 0;
            mCurrentView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
            int h = mCurrentView.getMeasuredHeight();
            if (h > height) height = h;
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
    
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        public void measureCurrentView(View currentView) {
            mCurrentView = currentView;
            this.post(new Runnable() {
                @Override
                public void run() {
                    requestLayout();
                }
            });
        }
    
        public int measureFragment(View view) {
            if (view == null)
                return 0;
    
            view.measure(0, 0);
            return view.getMeasuredHeight();
        }
    }
    
    
    public class MyPagerAdapter extends FragmentPagerAdapter {
    
        private List<Fragment> fragments;
        private int mCurrentPosition = -1;
    
    
        public MyPagerAdapter(FragmentManager fm) {
            super(fm);//or u can set them separately, but dont forget to call notifyDataSetChanged()
            this.fragments = new ArrayList<Fragment>();
            fragments.add(new FirstFragment());
            fragments.add(new SecondFragment());
            fragments.add(new ThirdFragment());
            fragments.add(new FourthFragment());
        }
    
        @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            super.setPrimaryItem(container, position, object);
            if (position != mCurrentPosition) {
                Fragment fragment = (Fragment) object;
                CustomPager pager = (CustomPager) container;
                if (fragment != null && fragment.getView() != null) {
                    mCurrentPosition = position;
                    pager.measureCurrentView(fragment.getView());
                }
            }
        }
    
        @Override
        public Fragment getItem(int position) {
            return fragments.get(position);
        }
    
        @Override
        public int getCount() {
            return fragments.size();
        }
    }
    

    fragments layout can be anything

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:orientation="vertical"
        android:layout_height="match_parent" tools:context="nevet.me.wcviewpagersample.FirstFragment">
    
    
        <ListView
            android:id="@+id/lv1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#991199"/>
    </LinearLayout>
    

    then somewhere just

    lv = (ListView) view.findViewById(R.id.lv1);
            lv.setAdapter(arrayAdapter);
            setListViewHeightBasedOnChildren(lv);
        }
    
        public static void setListViewHeightBasedOnChildren(ListView listView) {
            ListAdapter listAdapter = listView.getAdapter();
            if (listAdapter == null)
                return;
    
            int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(),
                    View.MeasureSpec.UNSPECIFIED);
            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,
                            LinearLayout.LayoutParams.WRAP_CONTENT));
    
                view.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
                totalHeight += view.getMeasuredHeight();
            }
            ViewGroup.LayoutParams params = listView.getLayoutParams();
            params.height = totalHeight
                    + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
            listView.setLayoutParams(params);
            listView.requestLayout();
        }
    
    0 讨论(0)
  • 2020-11-21 14:01

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

    In 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;
        }
    }
    
    0 讨论(0)
  • 2020-11-21 14:02
    listView.setOnTouchListener(new View.OnTouchListener() {
    
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        scrollView.requestDisallowInterceptTouchEvent(true);
    
        int action = event.getActionMasked();
    
        switch (action) {
            case MotionEvent.ACTION_UP:
                scrollView.requestDisallowInterceptTouchEvent(false);
                break;
        }
    
        return false;
    }
    });
    
    0 讨论(0)
  • 2020-11-21 14:03

    The shortest & easiest solution for any ChildView to scroll inside a ScrollView. Anything like ListView, RecyclerView, etc. You do not have to do anything special in code.

    Just replace ScrollView with androidx.core.widget.NestedScrollView in your current xml and then magic happens.

    Below is a sample xml code :

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.core.widget.NestedScrollView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <androidx.appcompat.widget.LinearLayoutCompat
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="16dp"
            android:paddingBottom="20dp">
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Recycler View inside a Scroll View"
                android:textColor="@color/black"
                android:textSize="@dimen/_20sp"
                android:textStyle="bold" />
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:text="Below is a Recycler View as an example."
                android:textSize="16sp" />
    
            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recycler_view"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                app:layout_constraintTop_toBottomOf="@id/et_damaged_qty" />
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:text="This textview automatically goes below the Recycler View."
                android:textSize="16sp" />
        </androidx.appcompat.widget.LinearLayoutCompat>
    </androidx.core.widget.NestedScrollView>
    

    Now you can get rid of all the ugly hacks we did to get around this nested scrolling.

    It's time to play. Hell Yeeeeeeeeeeeeeeeeeah!

    0 讨论(0)
  • 2020-11-21 14:03

    I know it's been so long but I got this problem too, tried this solution and it's working. So I guess it may help the others too.

    I add android:fillViewport="true" on the layout xml for the scrollView. So overall my ScrollView will be like this.

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

    And it works like magic to me. the ListView that located inside my ScrollView expand to its size again.

    Here is the full example code for the ScrollView and the 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>
    
    0 讨论(0)
提交回复
热议问题