写点什么

Flutter 扩展 NestedScrollView (二)列表滚动同步解决 (1)

用户头像
Android架构
关注
发布于: 10 小时前

position.applyFullDragUpdate(innerDelta);}} else {// dragging "down" - delta is positive// prioritize the inner views, so that the inner content will move before the app bar growsdouble outerDelta = 0.0; // it will go positive if it changesfinal List<double> overscrolls = <double>[];final List<_NestedScrollPosition> innerPositions = _innerPositions.toList();for (_NestedScrollPosition position in innerPositions) {final double overscroll = position.applyClampedDragUpdate(delta);outerDelta = math.max(outerDelta, overscroll);overscrolls.add(overscroll);}if (outerDelta != 0.0)outerDelta -= _outerPosition.applyClampedDragUpdate(outerDelta);// now deal with any overscrollfor (int i = 0; i < innerPositions.length; ++i) {final double remainingDelta = overscrolls[i] - outerDelta;if (remainingDelta > 0.0)innerPositions[i].applyFullDra


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


gUpdate(remainingDelta);}}}


Iterable<_NestedScrollPosition> get _innerPositions {return _innerController.nestedPositions;}


看到_innerPositions 是我们要关注的东西,通过 debug,我发现,如果 tabview 的每个 tab 做了缓存,那么每个 tab 里面列表的 ScrollPosition 将一直缓存在这个 ScrollController 里面。 当 tab 到 tabview 的某个 tab 的时候,ScrollController 将会将这 ScrollPosition attach 上,如果没有缓存,将会在离开的时候 detach 掉。


@overridevoid attach(ScrollPosition position) {assert(position is _NestedScrollPosition);super.attach(position);coordinator.updateParent();coordinator.updateCanDrag();position.addListener(_scheduleUpdateShadow);_scheduleUpdateShadow();}


@overridevoid detach(ScrollPosition position) {assert(position is _NestedScrollPosition);position.removeListener(_scheduleUpdateShadow);super.detach(position);_scheduleUpdateShadow();}



真相只有一个。。是的。。可以说。。造成缓存 tabview 的各个 tab 里面的列表互相影响的原因,是因为官方说: as design(我就是这样设计的,不服吗).


按照我的思想啊,我滚动的时候。当然只想影响当前显示的这个列表啊。这不科学啊。。


找到原因找到原理,一切就都好解决了。现在的关键点在于,我怎么能知道显示对应的是哪个列表的?!


这个问题问了很多人。。也查找了好久都没找到好的方式去获取当前 激活的 列表对应的 ScrollPosition。。终于我只能想到一个 workaround。暂时解决这个问题。


提供一个容器,把 inner 里面的滚动列表包裹起来,并且设置它的 tab 的唯一 key


//pack your inner scrollables which are in NestedScrollView body//so that it can find the active scrollable//compare with NestedScrollViewInnerScrollPositionKeyBuilderclass NestedScrollViewInnerScrollPositionKeyWidget extends StatefulWidget {final Key scrollPositionKey;final Widget child;NestedScrollViewInnerScrollPositionKeyWidget(this.scrollPositionKey, this.child);@override_NestedScrollViewInnerScrollPositionKeyWidgetState createState() =>_NestedScrollViewInnerScrollPositionKeyWidgetState();}


class _NestedScrollViewInnerScrollPositionKeyWidgetStateextends State<NestedScrollViewInnerScrollPositionKeyWidget> {@overrideWidget build(BuildContext context) {return widget.child;}


// @override// void didChangeDependencies() {// // TODO: implement didChangeDependencies// //print("didChangeDependencies"+widget.scrollPositionKey.toString());// super.didChangeDependencies();// }//// @override// void didUpdateWidget(NestedScrollViewInnerScrollPositionKeyWidget oldWidget) {// // TODO: implement didUpdateWidget// //print("didUpdateWidget"+widget.scrollPositionKey.toString()+oldWidget.scrollPositionKey.toString());// super.didUpdateWidget(oldWidget);// }}


然后在刚才 attach 方法中通过先祖 NestedScrollViewInnerScrollPositionKeyWidget


@overridevoid attach(ScrollPosition position) {assert(position is _NestedScrollPosition);


super.attach(position);attachScrollPositionKey(position as _NestedScrollPosition);coordinator.updateParent();coordinator.updateCanDrag();position.addListener(_scheduleUpdateShadow);_scheduleUpdateShadow();}


@overridevoid detach(ScrollPosition position) {assert(position is _NestedScrollPosition);position.removeListener(_scheduleUpdateShadow);super.detach(position);detachScrollPositionKey(position as _NestedScrollPosition);_scheduleUpdateShadow();}


void attachScrollPositionKey(_NestedScrollPosition position) {if (position != null && scrollPositionKeyMap != null) {var key = position.setScrollPositionKey();if (key != null) {if (!scrollPositionKeyMap.containsKey(key)) {scrollPositionKeyMap[key] = position;} else if (scrollPositionKeyMap[key] != position) {//in demo ,when tab to tab03, the tab02 key will be tab00 at first//then it become tab02.//this is not a good solution


position.clearScrollPositionKey();Future.delayed(Duration(milliseconds: 500), () {attachScrollPositionKey(position);});}}}}


void detachScrollPositionKey(_NestedScrollPosition position) {if (position != null &&scrollPositionKeyMap != null &&position.key != null &&scrollPositionKeyMap.containsKey(position.key)) {scrollPositionKeyMap.remove(position.key);position.clearScrollPositionKey();}}


获取先祖 NestedScrollViewInnerScrollPositionKeyWidget 方法


Key setScrollPositionKey() {//if (haveDimensions) {final type = _typeOf<NestedScrollViewInnerScrollPositionKeyWidget>();


NestedScrollViewInnerScrollPositionKeyWidget keyWidget =(this.context as ScrollableState)?.context?.ancestorWidgetOfExactType(type);_key = keyWidget?.scrollPositionKey;return _key;}


找到这个_NestedScrollCoordinator 的 applyUserOffset 方法中我们现在要替换掉 _innerPositions 为_currentInnerPositions


Iterable<_NestedScrollPosition> get _innerPositions {//return _currentPositions;return _innerController.nestedPositions;}


Iterable<_NestedScrollPosition> get _currentInnerPositions {return _innerController.getCurrentNestedPositions(innerScrollPositionKeyBuilder);}

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Flutter 扩展NestedScrollView (二)列表滚动同步解决(1)