ScrollView嵌套ListView,加载大量数据,界面卡顿问题的探讨

鄢博简
2023-12-01

之前使用ScrollView嵌套ListView,解决ScrollView嵌套ListView,列表项高度不同,显示不全的问题,现在发现一个问题,因为在ListView中计算各个列表项的高度,所以ListView实际上是全部展开的,这样的话,不能使用ListView重用的机制,如果数据过多,则列表绘制的时候,会出现卡顿,一段时间后才显示出来。

所以为了性能,就把界面重新优化,还是在ScrollView内使用ListView,不过固定好了ListView的高度,这样又会有一个问题,就是ScrollView和ListView滑动会冲突,这样又要解决掉滑动冲突的问题,点击ListView的时候,获取滑动控制权,点击其他地方,将控制权上交给ScrollView,进一步优化,如果ListView滑动到顶部或底部,将滑动控制权交给ScrollView,使ScrollView整体滑动。

下边是一些代码:lvSignservice 表示ListView

 /**
     * 处理ListView和ScrollView的滑动冲突问题,并且在列表滑动到顶部和底部的时候,滑动ScrollView
     *
     */
    private void dealWithListViewAndScrollViewTouch(){

        lvSignservice.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                lvSignservice.getParent().requestDisallowInterceptTouchEvent(true);
                return false;
            }
        });
        scrollview.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                scrollview.getParent().requestDisallowInterceptTouchEvent(false);
                return false;
            }
        });


        lvSignservice.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                if (firstVisibleItem == 0) {
                    View firstVisibleItemView = lvSignservice.getChildAt(0);
                    if (firstVisibleItemView != null && firstVisibleItemView.getTop() == 0) {
                        Log.d("ListView", "##### 滚动到顶部 #####");
                        lvSignservice.getParent().requestDisallowInterceptTouchEvent(false);
                        scrollview.getParent().requestDisallowInterceptTouchEvent(true);
                    }
                } else if ((firstVisibleItem + visibleItemCount) == totalItemCount) {
                    View lastVisibleItemView = lvSignservice.getChildAt(lvSignservice.getChildCount() - 1);
                    if (lastVisibleItemView != null && lastVisibleItemView.getBottom() == lvSignservice.getHeight()) {
                        Log.d("ListView", "##### 滚动到底部 ######");
                        lvSignservice.getParent().requestDisallowInterceptTouchEvent(false);
                        scrollview.getParent().requestDisallowInterceptTouchEvent(true);
                    }
                }
            }

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

        });
    }
 <FrameLayout android:layout_width="match_parent"
                         android:layout_height="400dp"
                         android:background="@color/white">
                <ListView
                        android:id="@+id/lv_signservice"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:cacheColorHint="#00000000"
                        android:divider="@null"/>
                <include layout="@layout/empty_layout"/>
            </FrameLayout>



ListView高度应该设置为match_parent,有利于优化,使用ListView的时候注意尽量使用layout_height=”match_parent”


其实,官方是不建议使用ScrollView嵌套ListView的:
You should never use a ScrollView with a ListView, because ListView takes care of its own vertical scrolling. Most importantly, doing this defeats all of the important optimizations in ListView for dealing with large lists, since it effectively forces the ListView to display its entire list of items to fill up the infinite container supplied by ScrollView.


不应该使用ScrollView嵌套ListView的,因为ListView会管理属于自己的垂直滚动。更重要的是,如果你这样做了,所有listview重要的优化都会被抵消掉,listview会被迫显示所有的item填满由ScrollView提供的容器。


如果真要嵌套的话,可以看解决ScrollView嵌套ListView,列表项高度不同,显示不全的问题,基本上两种方法,一个是手动计算item高度,一个是重写onMeasure方法。

个人经验:ScrollView嵌套ListView仅适合于ListView的item少的情况,如果数据过多,则要重新设计,将ListView上边的部分作为ListView的headView,要尽量使用ListView的重用机制
下边是一些参考文章:


Android开发之ScrollView中嵌套ListView的解决方案


【Android 非常基础】android官方不建议ScrollView嵌套ListView



Android应用性能优化系列视图篇——ListView自适应导致的严重性能问题


《Android APP要解决的问题》之显示篇:ScrollView嵌套ListView


Android 如何 ListView 判断滚动到最顶部或者底部

 类似资料: