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事件的。

时间: 2024-10-07 07:14:29

NestedScrollView嵌套ListView可行性总结的相关文章

NestedScrollView嵌套ListView滑动冲突

时间:2015年12月22日16:12:34 问题描述: 1)  在android.support.v4.widget.NestedScrollView中直接嵌套ListView时出现的情况:listview显示不全只有一行或者两行. 2) 如果listview的item中有根据id选择选项会导致选择错乱,现在(2015年12月22日16:13:55)碰到的问题是:listview中包含有switch控件, 用来对该item是否可用进行判断,但是现在冲突导致的listview中位置错乱. 2.解

NestedScrollView嵌套ListView时只显示一行的解决方法

在使用CoordinatorLayout和AppBarLayout实现嵌套滑动的时候,出现listview没有嵌套滑动: 如果要实现嵌套滑动,则需要添加NestedScrollView,但是结果发现listview只显示一行数据 <android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent"

GridView--scroolview嵌套listview和gridview

我们在真实项目中通常会遇到ListView或者GridView嵌套在ScrollView中问题.但是做的时候会发现,一旦两者进行嵌套,即会发生冲突.得不到我们希望的效果.由于ListView和GridView本身都继承于ScrollView,一旦在ScrollView中嵌套ScrollView,那么里面的ScrollView高度计算就会出现问题.我们也就无法得到想要的效果.下面进入正题,我们将分别讨论ScrollView中嵌套ListView和FGridView的情况: 核心解决方案: 重写Li

anroid中ScrollView嵌套ListView

有时候项目里面需要ScrollView嵌套ListView,但是正常下ListView只会显示一行多一点,解决方法就是填充ListView数据后重新计算ListView的高度,这里有两种方法来实现. 第一种方法:重写ListView [java] view plaincopyprint? package com.jwzhangjie.test; import android.content.Context; import android.util.AttributeSet; import and

四种方案解决ScrollView嵌套ListView问题(转)

在工作中,曾多次碰到ScrollView嵌套ListView的问题,网上的解决方法有很多种,但是杂而不全.我试过很多种方法,它们各有利弊. 在这里我将会从使用ScrollView嵌套ListView结构的原因.这个结构碰到的问题.几种解决方案和优缺点比较,这4个方面来为大家阐述.分析.总结. 实际上不光是ListView,其他继承自AbsListView的类也适用,包括ExpandableListView.GridView等等,为了方便说明,以下均用ListView来代表. 一. 为什么要使用S

当PullToRefreshScrollView里面嵌套ListView

当PullToRefreshScrollView里面嵌套ListView,ListView上面还是有内容的,当下拉刷新的 时候,数据填充完成之后ListView就会往上面滑动,导致ListView上面的数据没法显示,这个时候,我们能够设置ListView上面的控件获取焦点,就能够屏蔽掉ListView自己主动上滑的现象. title_tv.requestFocus(); title_tv.setFocusable(true); title_tv.setFocusableInTouchMode(t

四种方案解决ScrollView嵌套ListView问题

在工作中,曾多次碰到ScrollView嵌套ListView的问题,网上的解决方法有很多种,但是杂而不全.我试过很多种方法,它们各有利弊. 在这里我将会从使用ScrollView嵌套ListView结构的原因.这个结构碰到的问题.几种解决方案和优缺点比较,这4个方面来为大家阐述.分析.总结. 实际上不光是ListView,其他继承自AbsListView的类也适用,包括ExpandableListView.GridView等等,为了方便说明,以下均用ListView来代表. 一. 为什么要使用S

ScrollView嵌套ListView问题

ScrollView嵌套ListView问题 导致Listview  首先导致的 是 Listview 的item 条数显示不完全, 这是因为item 中的 Textview 字数太多的问题 一定要注意 item 是 线性布局 ,二 item 中的 Textview 自动换行也会导致 item 条数显示不正确, 所以 有了如下的解决办法 1,保证 item 是 线性布局, 2. 重写Listview ,代码如下 : public class MyWuliuLsitview extends Lis

android listview左右滑动分页(viewpager嵌套listview进行分页),焦点图带圆焦点

1.先上图后说话 2.代码 package com.example.exmp; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.os.Parcelable; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import and