想做到这么一种效果,页面中既有轮播图,又有RecyclerView,当RecyclerView上滑时,轮播图会消失。
而这样就会出现一个问题。
打印出log,分别在适配器中的onBindViewHolder和onCreateViewHolder 也打印log。
这里准备的数据有52条,结果这一下全部加载出来了,这样就造成内存吃紧的情况。
而且我们加载更多数据的时候,也会出现这种情况。
按照我们正常的RecyclerView的使用,我们的onCreateViewHolder 不会有么多次的调用,只会有展示窗口的大小能容纳下的item个数。
onBindViewHolder 是正常的,它会每次给展示的几个item 动态更换内容,从而完成对item的复用。
但是这里每一次都会调用(它的调用就意味着对象的创建)。这就问题蛮大了。
通过获得Recyclerview的高度,就会发现Recyclerview高度有点长的过分了。
这里的问题就在于NestedScrollView嵌套RecyclerView 会出现这情况。
因为NestedScrollView,导致RecyclerView 全部加载出来了。
只需要给我们的RecyclerView 动态的设置一个固定的长度。这样RecyclerView就能根据手机屏幕展示的大小,从而简单的调用几个onCreateViewHolder()。不会想之前那样多次调用了。
怎么解决已经有了思路,就获得屏幕长度即可,这里说的屏幕长度,是指的完全展示RecyclerView所需的长度。(这里因为因为可能存在一些标题栏,底部导航栏,因为这些东西是一直保持展示的)完全展示RecyclerView所需的长度 就等于 屏幕的长度 减去 刚刚说的东西的高度。
得到包裹RecyclerView的父控件。然后通过他的 viewTreeObserver 添加一个OnGlobalLayoutListener。
在这个监听器中的onGlobalLayout方法中,然后就可以获得父控件的measuredHeight,将这长度获得通过layoutParams 给设置 RecyclerView 。
…
这里设置后,又又又出问题了。
轮播图不会被顶上去了。
这里需要完成他们两的滑动通讯。
上面它们实现的接口正是完成通讯的关键,
其中NestedScrollView 实现了一个NestedScrollingParent3的接口,
RecyclerView 实现了一个NestedScrollingChild3的接口,这就构成了一个父子关系。
在RecyclerView中有一个NestedScrollingChildHelper 对象
通过查找这个对象,我们可以找到上面框中的方法,为对象进行了赋值。
通过查找这个方法名,我们可以知道有什么调用了这个方法。
这些方法通过方法名就大概能了解到意思了。
看其中的一个dispatchNestedScroll()方法,这是对嵌套滚动事件进行分发。
通过查看这个dispatchNestedScroll()方法在什么地方调用。
可以看到这个方法在scrollByInternal()中进行了调用的。
而这个scrollByInternal()方法又被scrollBy()方法调用,这个方法就会在滑动的时候就行调用了。
从scrollBy()方法回溯,在dispatchNestedScroll()方法中,就调用了 getScrollingChildHelper().dispatchNestedScroll()这个方法。
而getScrollingChildHelper()这个方法正是返回一个NestedScrollingChildHelper 对象(也就是最先的说的那个对象)。虽然开始不清楚为啥找这个对象,但是如果我们直接从scrollBy开始想,就会清楚很多。
随后就进入了NestedScrollingChildHelper 这个类中,调用了他的dispatchNestedScroll()方法。
dispatchNestedScroll中也就调用了dispatchNestedScrollInternal()。
这个时候重点来了:在dispatchNestedScrollInternal方法中通过调用getNestedScrollingParentForType()就得到了RecyclerView的父控件(这里说的父控件是上面通过NestedScrollingParent3和NestedScrollingChild3这对接口构成的父子关系),这个父控件就是NestedScrollView。
验证方法,我们可以直接写一个继承于NestedScrollView的类,重写他的onNestedScroll()方法,打印日志,会发现滑动的时候这个方法也会调用,在刚刚的getNestedScrollingParentForType()打一个端点查看就知道这里确实获取到了对应的父类。
现在就还有一个问题:这里怎么实现寻找到这个父控件的呢?
接着看下面的 ViewParentCompat.onNestedScroll()方法,这里将parent穿进去了。
但是这个方法中还传入了一个mView 这个mView是什么呢?
查看mView的赋值,通过下面的提示,我们知道这不就RecyclerView本身吗?
这里是在RecyclerView中调用的传入的是this。
接着看 ViewParentCompat.onNestedScroll()的实现,这里parent是NestedScrollView,target的RecyclerView,因为parent的接口实现,所以会执行红框中的方法。
这里红框中调用的是parent的onNestedScroll()
如果能对parent的onNestedScroll()的方法进行控制就可以解决这个滑动问题了。
具体的视频演示:梳理NestedScrollView嵌套RecyclerView的滑动通讯
通过重写两个接口的方法就可以解决这个问题(前提我们需要用自己的继承于NestedScrollView的类来完成)是我所学习到的一种方法,不排除其他。
就上面的两个接口方法。
通过onScrollChanged 获得NestedScrollView滑动了多少距离。
在 onNestedPreScroll 方法中处理 。 从上面获得的距离可以判断头部的部分(即轮播图)是否完全隐藏了。没有隐藏的话,就让NestedScrollView整体滑动,隐藏后,就将滑动的事件分发给RecyclerView去实现。
这里通过设置了一个方法来获取外面的头部部分的高度。
附上视频吧;这是我在视频中学习的东西,这里做一下记录,分享给大家看看。
第一部分
第二部分
第三部分
第四部分