zoukankan      html  css  js  c++  java
  • NestedScrollView嵌套ListView可行性总结

    由于公司项目遗留代码仍然使用PullToRefreshListView(后文简称PTRLV),且存在复用,更换RecyclerView成本太大,同时又想使用CoordinatorLayout来实现一些嵌套滑动效果,所以研究了NestedScrollView嵌套PTRLV的方案。

    对于NestedScrollView嵌套普通的ListView,常见的问题有:

    1. 嵌套后ListView只显示一行。
    2. ListView无法滑动。

    网上的解决方案主要是2种:

    1. 重写ListView的onMeasure方法。

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
         super.onMeasure(widthMeasureSpec, expandSpec);
     }

    将ListView所有子View的高度以及分隔线的高度相加,重新设置给ListView。

    private void setListViewHeightBasedOnChildren(ListView listView) {
         ListAdapter listAdapter = listView.getAdapter(); //获得Adapter
         if (listAdapter == null) { 
             return;
         }
         int totalHeight = 0;
         for (int i = 0; i < listAdapter.getCount(); i++) {
             View listItem = listAdapter.getView(i, null, listView);
             listItem.measure(0, 0);
             totalHeight += listItem.getMeasuredHeight();
         }
         ViewGroup.LayoutParams params = listView.getLayoutParams();
         params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
         listView.setLayoutParams(params);
     }
    1. 这种方法要求子View的根布局必须是LinearLayout。

    这2种方法乍看之下也都能解决NestedScrollView嵌套PTRLV的问题,但其实局限性很大,项目中实践后发现场景稍有变化就仍然有问题。

    主要有:

    1. 有些场景下展示的数据并不会在Activity的onCreate方法中就获取,例如搜索页需要用户输入关键字后才去获取数据,然后才将数据给到PTRLV展示,这时PTRLV只显示半行。
    2. 在PTRLV中改写添加的预加载功能失效。

    第1个问题出现的原因在于,上述2种解决方案都是改变PTRLV中真正的ListView的大小,让它能够将全部的子View展现出来。在这个场景中,界面初始化时,ListView中是没有数据的,所以在measure时ListView本身大小为0,只测量出了PTRLV的那个滑动指示块的高度,所以PTRLV只有那么高。

    那为什么获取到数据后再notify还是只有这么高呢?因为PTRLV在真正的ListView之外还有两层FrameLayout。虽然ListView因为重写了onMeasure方法已经展示全了,但这两层FrameLayout还是只有滑块那么高,所以PTRLV看起来还是没有改变。

    解决方案为:
    重写PTRLV内部的FrameLayout的onMeasure方法,跟ListView一样就行

    public class NoScrollFrameLayout extends FrameLayout {
    
        public NoScrollFrameLayout(Context context) {
            super(context);
        }
    
        public NoScrollFrameLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, expandSpec);
        }
    }

    在PTRLV的父类PullToRefreshBase中改写addRefreshableView方法

    private void addRefreshableView(Context context, T refreshableView) {
        mRefreshableViewWrapper = new NoScrollFrameLayout(context);
        mRefreshableViewWrapper.addView(refreshableView, ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT);
    
        addViewInternal(mRefreshableViewWrapper, new LayoutParams(LayoutParams.MATCH_PARENT,
            LayoutParams.MATCH_PARENT));
    }

    第2个问题出现的原因是因为滑动事件的冲突。这里可能会有疑问,为什么还说滑动事件有冲突,通过上述方案不是已经可以正常滑动了吗?那是因为那只是看上去像ListView的滑动,其实是NestedSrcollView在滑动,ListView根本没有动。

    从第1个问题的原因中我们已经知道了,解决NestedScrollView中嵌套ListView显示不全问题的方法,其本质都是手动修改ListView的内容的高度,而且不是将高度match_parent,而是将ListView的子View全部加载进来,假如有50个数据,就一次性加载50个子View,所以ListView就相当于一个有50个子View的LinearLayout。(当然也就不会有复用,性能很差)

    另一方面,NestedSrcollView在onInterceptTouchEvent中拦截了所有的Touch事件,ListView没有分发到任何事件,所以虽然看上去像ListView在滑动,实际上是ScrollView包裹着相当于LinearLayout的ListView在滑动,而由于我们项目的预加载逻辑写在ListView的onScrollStateChange方法中,没有分到任何Touch事件的情况下根本不会调用onScrollStateChange,因此预加载就失效了。

    这个问题在不改动预加载逻辑实现位置的情况下是无解的。同时也可以得出:如果你在ListView的Touch事件中有自定义的逻辑,那么请不要用NestedSrcollView嵌套ListView,因为NestedSrcollView会拦截Touch事件,所有的滑动解决方案并没有真正解决滑动冲突,ListView是获取不到Touch事件的。

  • 相关阅读:
    托付和事件的使用
    在使用supervisord 管理tomcat时遇到的小问题
    无法安装vmware tools的解决方PLEASE WAIT! VMware Tools is currently being installed on your system. Dependin
    (转)Openlayers 2.X加载高德地图
    (转)openlayers实现在线编辑
    (转) Arcgis for js加载百度地图
    (转)Arcgis for js加载天地图
    (转) 基于Arcgis for Js的web GIS数据在线采集简介
    (转) Arcgis for js之WKT和GEOMETRY的相互转换
    (转)Arcgis for Js之Graphiclayer扩展详解
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/7371735.html
Copyright © 2011-2022 走看看