Android ScrollView 嵌套 RecyclerView 问题

01.可能出现的问题

  • 实际开发中,要实现在NestedScrollView中嵌入一个或多个RecyclerView。这一做法通常会导致如下几个问题
    • 页面滑动卡顿
    • ScrollView高度显示不正常
    • RecyclerView内容显示不全
    • NestedScrollView滚动不到顶部

02.滑动卡顿问题

  • 若只存在滑动卡顿这一问题,可以采用如下两种简单方式快速解决。

  • 第一种方法:利用RecyclerView内部方法

    • 需要设置方法如下所示。这个方法主要是设置RecyclerView不处理滚动事件,全部交由ScorllView去处理,这样就解决了滑动卡顿的问题。
    1
    2
    recyclerView.setHasFixedSize(true);
    recyclerView.setNestedScrollingEnabled(false);
    • 其中,setHasFixedSize(true)方法使得RecyclerView能够固定自身size不受adapter变化的影响;而setNestedScrollingeEnabled(false)方法则是进一步调用了RecyclerView内部NestedScrollingChildHelper对象的setNestedScrollingeEnabled(false)方法,如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public void setNestedScrollingEnabled(boolean enabled) {
    this.getScrollingChildHelper().setNestedScrollingEnabled(enabled);
    }


    public void setNestedScrollingEnabled(boolean enabled) {
    if (this.mIsNestedScrollingEnabled) {
    //NestedScrollingChildHelper对象通过该方法关闭RecyclerView的嵌套滑动特性
    ViewCompat.stopNestedScroll(this.mView);
    }

    this.mIsNestedScrollingEnabled = enabled;
    }
  • 第二种方法:重写LayoutManager。

    • RecyclerView的垂直滑动始终返回false,其目的同样是为了限制自身的滑动
    1
    2
    3
    4
    5
    6
    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this) {
    @Override
    public boolean canScrollVertically() {
    return false;
    }
    };

03.解决卡顿和显示问题

  • 有时候上面说的几种情况都存在,或者说都需要解决,那么综合解决办法如下所示:

    • 页面滑动卡顿
    • ScrollView高度显示不正常
    • RecyclerView内容显示不全
    • NestedScrollView滚动不到顶部
  • 第一种解决办法

    • 设置recyclerView不处理滚动事件,并且在布局中嵌套一层LinearLayout/RelativeLayout解决焦点抢占问题。

    • 网上有方案说是因为RecyclerView抢了焦点,自动滑动,只需要在xml页面在最顶层的View加入下面代码。发现并不好使!

      1
      2
      android:focusableInTouchMode="true"
      android:focusable="true"
    • 设置descendantFocusability属性。使用网上的方法一种是使用 RelativeLayout 包裹 RecyclerView 并设置属性:android:descendantFocusability=”blocksDescendants”

      • android:descendantFocusability=”blocksDescendants”,该属>性是当一个view 获取焦点时,定义 ViewGroup 和其子控件直接的关系,常用来>解决父控件的焦点或者点击事件被子空间获取。
      • beforeDescendants: ViewGroup会优先其子控件获取焦点
      • afterDescendants: ViewGroup只有当其子控件不需要获取焦点时才获取焦点
      • blocksDescendants: ViewGroup会覆盖子类控件而直接获得焦点
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      <RelativeLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:descendantFocusability="blocksDescendants">
      <android.support.v7.widget.RecyclerView
      android:id="@+id/rv_hot_review"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:foregroundGravity="center" />
      </RelativeLayout>
    • 注意,之后尝试不用嵌套布局也可以实现滚动冲突问题

      1
      2
      3
      4
      5
      <android.support.v7.widget.RecyclerView
      android:id="@+id/rv_hot_review"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:descendantFocusability="blocksDescendants" />

04.使用嵌套建议

  • 尽管我们能够采用多种方式解决ScrollView嵌套RecyclerView所产生的一系列问题,但由于上述解决方式均会使得RecyclerView在页面加载过程中一次性显示所有内容,因此当RecyclerView下的条目过多时,将会对影响整个应用的运行效率。基于此,在这种情况下我们应当尽量避免采用ScrollView嵌套RecyclerView的布局方式