diff --git a/lib/shop/shop_scroll_controller.dart b/lib/shop/shop_scroll_controller.dart index f987c38..0992189 100644 --- a/lib/shop/shop_scroll_controller.dart +++ b/lib/shop/shop_scroll_controller.dart @@ -4,58 +4,65 @@ import 'package:flutter/widgets.dart'; import 'shop_scroll_coordinator.dart'; import 'shop_scroll_position.dart'; -/// 滑动控制器 +/// 滑动控制器。为可滚动小部件创建一个控制器。 +/// +/// [initialScrollOffset] 和 [keepScrollOffset] 的值不能为 null。 class ShopScrollController extends ScrollController { - final ShopScrollCoordinator coordinator; - - /// 为可滚动小部件创建一个控制器。 - /// `initialScrollOffset`和`keepScrollOffset`的值不能为null。 ShopScrollController( this.coordinator, { double initialScrollOffset = 0.0, - this.keepScrollOffset = true, - this.debugLabel, + + /// 每次滚动完成时,请使用 [PageStorage] 保存当前滚动 [offset] ,如果重新创建了此 + /// 控制器的可滚动内容,则将其还原。 + /// + /// 如果将此属性设置为false,则永远不会保存滚动偏移量, + /// 并且始终使用 [initialScrollOffset] 来初始化滚动偏移量。如果为 true(默认值), + /// 则第一次创建控制器的可滚动对象时将使用初始滚动偏移量,因为尚无要还原的滚动偏移量。 + /// 随后,将恢复保存的偏移,并且忽略[initialScrollOffset]。 + /// + /// 也可以看看: + /// * [PageStorageKey],当同一路径中出现多个滚动条时,应使用 [PageStorageKey] + /// 来区分用于保存滚动偏移量的 [PageStorage] 位置。 + bool keepScrollOffset = true, + + /// [toString] 输出中使用的标签。帮助在调试输出中标识滚动控制器实例。 + String debugLabel, }) : assert(initialScrollOffset != null), assert(keepScrollOffset != null), - _initialScrollOffset = initialScrollOffset; + _initialScrollOffset = initialScrollOffset, + super(keepScrollOffset: keepScrollOffset, debugLabel: debugLabel); - /// 用于[offset]的初始值。 - /// 如果[keepScrollOffset]为false或尚未保存滚动偏移量, - /// 则创建并附加到此控制器的新[ScrollPosition]对象的偏移量将初始化为该值。 - /// 默认为0.0。 + final ShopScrollCoordinator coordinator; + + /// 用于 [offset] 的初始值。 + /// 如果 [keepScrollOffset] 为 false 或尚未保存滚动偏移量, + /// 则创建并附加到此控制器的新 [ShopScrollPosition] 对象的偏移量将初始化为该值。 + /// 默认为 0.0。 + @override double get initialScrollOffset => _initialScrollOffset; final double _initialScrollOffset; - /// 每次滚动完成时,请使用[PageStorage]保存当前滚动[offset],如果重新创建了此控制器的可滚动内容,则将其还原。 - /// - /// 如果将此属性设置为false,则永远不会保存滚动偏移量,并且始终使用[initialScrollOffset] - /// 来初始化滚动偏移量。 如果为true(默认值),则第一次创建控制器的可滚动对象时将使用初始 - /// 滚动偏移量,因为尚无要还原的滚动偏移量。 随后,将恢复保存的偏移,并且忽略[initialScrollOffset]。 + /// 当前附加的 [positions]。 /// - /// 也可以看看: - /// * [PageStorageKey],当同一路径中出现多个滚动条时,应使用[PageStorageKey] - /// 来区分用于保存滚动偏移量的[PageStorage]位置。 - final bool keepScrollOffset; - - /// [toString]输出中使用的标签。 旨在帮助在调试输出中标识滚动控制器实例。 - final String debugLabel; - - /// The currently attached positions. 当前附加的 [positions]。 - /// 这不应直接突变。 可以使用[attach]和[detach]添加和删除[ScrollPosition]对象。 + /// 不应直接突变。 + /// 可以使用 [attach] 和 [detach] 添加和删除 [ShopScrollPosition] 对象。 @protected - Iterable get positions => _positions; - final List _positions = []; + @override + Iterable get positions => _positions; + final List _positions = []; - /// 是否有任何[ScrollPosition]对象已使用[attach]方法将自身附加到[ScrollController]。 + /// 是否有任何 [ShopScrollPosition] 对象已使用 [attach] 方法 + /// 将自身附加到 [ScrollController]。 /// - /// 如果为false,则不得调用与[ScrollPosition]交互的成员, - /// 例如[position],[offset],[animateTo]和[jumpTo]。 + /// 如果为 false,则不得调用与 [ShopScrollPosition] 交互的成员, + /// 例如 [position],[offset],[animateTo] 和 [jumpTo]。 + @override bool get hasClients => _positions.isNotEmpty; /// 返回附加的[ScrollPosition],可以从中获取[ScrollView]的实际滚动偏移量。 /// - /// Calling this is only valid when only a single position is attached. - /// 仅在仅连接一个[position]时调用此选项才有效。 + /// 仅在仅连接一个 [position] 时调用此选项才有效。 + @override ShopScrollPosition get position { assert(_positions.isNotEmpty, 'ScrollController not attached to any scroll views.'); @@ -64,60 +71,71 @@ class ShopScrollController extends ScrollController { return _positions.single; } - /// 可滚动小部件的当前滚动偏移量 /// 可滚动小部件的当前滚动偏移量。要求控制器仅控制一个可滚动小部件。 + @override double get offset => position.pixels; /// 从当前位置到给定值的位置动画。 /// 任何活动的动画都将被取消。 如果用户当前正在滚动,则该操作将被取消。 - /// 返回的[Future]将在动画结束时完成,无论它是否成功完成或是否被过早中断。 + /// 返回的 [Future] 将在动画结束时完成,无论它是否成功完成或是否被过早中断。 /// - /// 每当用户尝试手动滚动或启动其他活动,或者动画到达视口边缘并尝试过度滚动时,动画都会中断。 - /// (如果[ScrollPosition]不会过度滚动,而是允许滚动超出范围,那么超出范围不会中断动画。) + /// 每当用户尝试手动滚动或启动其他活动,或者动画到达视口边缘并尝试过度滚动时, + /// 动画都会中断。如果 [ShopScrollPosition] 不会过度滚动,而是允许滚动超出范围, + /// 那么超出范围不会中断动画。 /// /// 动画对视口或内容尺寸的更改无动于衷。 /// /// 一旦动画完成,如果滚动位置的值不稳定,则滚动位置将尝试开始弹道活动。 /// (例如,如果滚动超出范围,并且在这种情况下滚动位置通常会弹回) /// - /// 持续时间不能为零。 要在没有动画的情况下跳至特定值,请使用[jumpTo]。 + /// 持续时间不能为零。要在没有动画的情况下跳至特定值,请使用 [jumpTo]。 + @override Future animateTo( double offset, { @required Duration duration, @required Curve curve, }) { - assert(_positions.isNotEmpty, - 'ScrollController not attached to any scroll views.'); + assert( + _positions.isNotEmpty, + 'ScrollController not attached to any scroll views.', + ); final List> animations = List>(_positions.length); for (int i = 0; i < _positions.length; i += 1) - animations[i] = - _positions[i].animateTo(offset, duration: duration, curve: curve); + animations[i] = _positions[i].animateTo( + offset, + duration: duration, + curve: curve, + ); return Future.wait(animations).then((List _) => null); } /// 将滚动位置从其当前值跳转到给定值,而不进行动画处理,也无需检查新值是否在范围内。 /// 任何活动的动画都将被取消。 如果用户当前正在滚动,则该操作将被取消。 /// - /// 如果此方法更改了滚动位置,则将分派开始/更新/结束滚动通知的序列。 此方法不能生成过滚动通知。 - /// - /// 跳跃之后,如果数值超出范围,则立即开始弹道活动。 + /// 如果此方法更改了滚动位置,则将分派开始/更新/结束滚动通知的序列。 + /// 此方法不能生成过滚动通知。跳跃之后,如果数值超出范围,则立即开始弹道活动。 + @override void jumpTo(double value) { - assert(_positions.isNotEmpty, - 'ScrollController not attached to any scroll views.'); - for (ScrollPosition position in List.from(_positions)) + assert( + _positions.isNotEmpty, + 'ScrollController not attached to any scroll views.', + ); + for (final ScrollPosition position in List.from(_positions)) position.jumpTo(value); } /// 在此控制器上注册给定位置。 - /// 此函数返回后,此控制器上的[animateTo]和[jumpTo]方法将操纵给定位置。 - void attach(ScrollPosition position) { + /// 此函数返回后,此控制器上的 [animateTo] 和 [jumpTo] 方法将操纵给定位置。 + @override + void attach(covariant ShopScrollPosition position) { assert(!_positions.contains(position)); _positions.add(position); position.addListener(notifyListeners); } /// 用此控制器注销给定位置。 - /// 此函数返回后,此控制器上的[animateTo]和[jumpTo]方法将不会操纵给定位置。 + /// 此函数返回后,此控制器上的 [animateTo] 和 [jumpTo] 方法将不会操纵给定位置。 + @override void detach(ScrollPosition position) { assert(_positions.contains(position)); position.removeListener(notifyListeners); @@ -126,30 +144,35 @@ class ShopScrollController extends ScrollController { @override void dispose() { - for (ScrollPosition position in _positions) + for (final ScrollPosition position in _positions) position.removeListener(notifyListeners); super.dispose(); } - /// 创建一个[ScrollPosition]供[Scrollable]小部件使用。 + /// 创建一个 [ShopScrollPosition] 供 [Scrollable] 小部件使用。 /// - /// 子类可以重写此功能,以自定义其控制的可滚动小部件使用的[ScrollPosition]。 - /// 例如,[PageController]重写此函数以返回面向页面的滚动位置子类, + /// 子类可以重写此功能,以自定义其控制的可滚动小部件使用的 [ShopScrollPosition]。 + /// 例如,[PageController] 重写此函数以返回面向页面的滚动位置子类, /// 该子类在可滚动窗口小部件调整大小时保持同一页面可见。 /// - /// 默认情况下,返回[ScrollPositionWithSingleContext]。 - /// 参数通常传递给正在创建的[ScrollPosition]: + /// 默认情况下,返回 [ScrollPositionWithSingleContext]。 + /// 参数通常传递给正在创建的 [ScrollPosition]: /// - /// * `physics`:[ScrollPhysics]的一个实例,它确定[ScrollPosition]对用户交互的反应方式, - /// 释放或甩动时如何模拟滚动等。该值不会为null。 它通常来自[ScrollView]或其他创建 - /// [Scrollable]的小部件,或者(如果未提供)来自环境[ScrollConfiguration]。 - /// * `context`:一个[ScrollContext],用于与拥有[ScrollPosition]的对象进行通信 - /// (通常是[Scrollable]本身)。 - /// * `oldPosition`: 如果这不是第一次为此[Scrollable]创建[ScrollPosition], - /// 则它将是前一个实例。 当环境已更改并且[Scrollable]需要重新创建[ScrollPosition] - /// 对象时,将使用此方法。 第一次创建[ScrollPosition]时为null。 - ScrollPosition createScrollPosition(ScrollPhysics physics, - ScrollContext context, ScrollPosition oldPosition) { + /// * [physics]:[ScrollPhysics] 的一个实例,它确定 [ScrollPosition] 对用户交互的 + /// 反应方式,释放或甩动时如何模拟滚动等。该值不会为null。它通常来自 [ScrollView] + /// 或其他创建 [Scrollable]的小部件, + /// 或者(如果未提供)来自环境的 [ScrollConfiguration]。 + /// * [context]:一个 [ScrollContext],用于与拥有 [ScrollPosition] 的对象进行通信 + /// (通常是 [Scrollable] 本身)。 + /// * [oldPosition]:如果这不是第一次为此 [Scrollable] 创建 [ScrollPosition],则 + /// 它将是前一个实例。当环境已更改并且 [Scrollable] 需要重新创建 [ScrollPosition] + /// 对象时,将使用此方法。 第一次创建 [ScrollPosition] 时为 null。 + @override + ShopScrollPosition createScrollPosition( + ScrollPhysics physics, + ScrollContext context, + ScrollPosition oldPosition, + ) { return ShopScrollPosition( coordinator: coordinator, physics: physics, @@ -168,21 +191,25 @@ class ShopScrollController extends ScrollController { return '${describeIdentity(this)}(${description.join(", ")})'; } - /// 在给定的描述中添加其他信息,以供[toString]使用。 - /// 此方法使子类更易于协调以提供高质量的[toString]实现。 [ScrollController] - /// 基类上的[toString]实现调用[debugFillDescription]来从子类中收集有用的信息,以合并到其返回值中。 - /// 如果您重写了此方法,请确保通过调用`super.debugFillDescription(description)`来启动方法。 + /// 在给定的描述中添加其他信息,以供 [toString] 使用。 + /// 此方法使子类更易于协调以提供高质量的 [toString] 实现。[ScrollController] 基类上 + /// 的 [toString] 实现调用 [debugFillDescription] 来从子类中收集有用的信息,以合并 + /// 到其返回值中。如果您重写了此方法,请确保通过调用 + /// `super.debugFillDescription)description)` 来启动方法。 + @override @mustCallSuper void debugFillDescription(List description) { super.debugFillDescription(description); - if (debugLabel != null) description.add(debugLabel); + if (debugLabel != null) { + description.add(debugLabel); + } if (initialScrollOffset != 0.0) description.add( 'initialScrollOffset: ${initialScrollOffset.toStringAsFixed(1)}, '); if (_positions.isEmpty) { description.add('no clients'); } else if (_positions.length == 1) { - // 实际上不列出客户端本身,因为它的toString可能引用了我们。 + // 实际上不列出客户端本身,因为它的 toString 可能引用了我们。 description.add('one client, offset ${offset?.toStringAsFixed(1)}'); } else { description.add('${_positions.length} clients'); diff --git a/lib/shop/shop_scroll_coordinator.dart b/lib/shop/shop_scroll_coordinator.dart index 624dbeb..a235d66 100644 --- a/lib/shop/shop_scroll_coordinator.dart +++ b/lib/shop/shop_scroll_coordinator.dart @@ -1,5 +1,5 @@ import 'dart:math' as math; -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'shop_scroll_controller.dart'; @@ -8,9 +8,10 @@ import 'shop_scroll_position.dart'; enum PageExpandState { NotExpand, Expanding, Expanded } /// 协调器 +/// +/// 页面 Primary [CustomScrollView] 控制 class ShopScrollCoordinator { - /// 页面主 CustomScrollView 控制 - final String pageLabel = "page"; + final String pageLabel = 'page'; ShopScrollController _pageScrollController; double Function() pinnedHeaderSliverHeightBuilder; @@ -26,8 +27,11 @@ class ShopScrollCoordinator { ShopScrollController pageScrollController([double initialOffset = 0.0]) { assert(initialOffset != null, initialOffset >= 0.0); _pageInitialOffset = initialOffset; - _pageScrollController = ShopScrollController(this, - debugLabel: pageLabel, initialScrollOffset: initialOffset); + _pageScrollController = ShopScrollController( + this, + debugLabel: pageLabel, + initialScrollOffset: initialOffset, + ); return _pageScrollController; } @@ -36,20 +40,25 @@ class ShopScrollCoordinator { ShopScrollController(this, debugLabel: debugLabel); /// 子部件滑动数据协调 - /// [userScrollDirection]用户滑动方向 - /// [position]被滑动的子部件的位置信息 - void applyUserOffset(double delta, - [ScrollDirection userScrollDirection, ShopScrollPosition position]) { + /// + /// [userScrollDirection] 用户滑动方向 + /// [position] 被滑动的子部件的位置信息 + void applyUserOffset( + double delta, [ + ScrollDirection userScrollDirection, + ShopScrollPosition position, + ]) { if (userScrollDirection == ScrollDirection.reverse) { updateUserScrollDirection(_pageScrollPosition, userScrollDirection); - final innerDelta = _pageScrollPosition.applyClampedDragUpdate(delta); + final double innerDelta = + _pageScrollPosition.applyClampedDragUpdate(delta); if (innerDelta != 0.0) { updateUserScrollDirection(position, userScrollDirection); position.applyFullDragUpdate(innerDelta); } } else { updateUserScrollDirection(position, userScrollDirection); - final outerDelta = position.applyClampedDragUpdate(delta); + final double outerDelta = position.applyClampedDragUpdate(delta); if (outerDelta != 0.0) { updateUserScrollDirection(_pageScrollPosition, userScrollDirection); _pageScrollPosition.applyFullDragUpdate(outerDelta); @@ -69,7 +78,7 @@ class ShopScrollCoordinator { /// 当默认位置不为0时,主部件已下拉距离超过默认位置,但超过的距离不大于该值时, /// 若手指离开屏幕,主部件头部会回弹至默认位置 - double _scrollRedundancy = 80; + final double _scrollRedundancy = 80; /// 当前页面Header最大程度展开状态 PageExpandState pageExpand = PageExpandState.NotExpand; @@ -81,15 +90,21 @@ class ShopScrollCoordinator { if (pageExpand == PageExpandState.NotExpand && _pageInitialOffset - _pagePixels > _scrollRedundancy) { _pageScrollPosition - .animateTo(0.0, - duration: const Duration(milliseconds: 400), curve: Curves.ease) - .then((value) => pageExpand = PageExpandState.Expanded); + .animateTo( + 0.0, + duration: const Duration(milliseconds: 400), + curve: Curves.ease, + ) + .then((_) => pageExpand = PageExpandState.Expanded); } else { pageExpand = PageExpandState.Expanding; _pageScrollPosition - .animateTo(_pageInitialOffset, - duration: const Duration(milliseconds: 400), curve: Curves.ease) - .then((value) => pageExpand = PageExpandState.NotExpand); + .animateTo( + _pageInitialOffset, + duration: const Duration(milliseconds: 400), + curve: Curves.ease, + ) + .then((_) => pageExpand = PageExpandState.NotExpand); } } } @@ -101,10 +116,12 @@ class ShopScrollCoordinator { position.didUpdateScrollDirection(value); } - /// 以特定的速度开始一个物理驱动的模拟,该模拟确定[pixels]位置。 - /// 此方法遵从[ScrollPhysics.createBallisticSimulation],该方法通常在当前位置超出 - /// 范围时提供滑动模拟,而在当前位置超出范围但具有非零速度时提供摩擦模拟。 - /// 速度应以每秒逻辑像素为单位。 + /// 以特定的速度开始一个物理驱动的模拟,该模拟确定 [pixels] 位置。 + /// + /// 此方法遵从 [ScrollPhysics.createBallisticSimulation],通常在当前位置超出范围时 + /// 提供滑动模拟,而在当前位置超出范围但具有非零速度时提供摩擦模拟。 + /// + /// 速度应以 逻辑像素/秒 为单位。 void goBallistic(double velocity) => _pageScrollPosition.goBallistic(velocity); } diff --git a/lib/shop/shop_scroll_position.dart b/lib/shop/shop_scroll_position.dart index f114796..d3db5f2 100644 --- a/lib/shop/shop_scroll_position.dart +++ b/lib/shop/shop_scroll_position.dart @@ -10,19 +10,15 @@ import 'shop_scroll_coordinator.dart'; /// 滑动位置信息 class ShopScrollPosition extends ScrollPosition implements ScrollActivityDelegate { - final ShopScrollCoordinator coordinator; // 协调器 - ScrollDragController _currentDrag; - double _heldPreviousVelocity = 0.0; - - ShopScrollPosition( - {@required ScrollPhysics physics, - @required ScrollContext context, - double initialPixels = 0.0, - bool keepScrollOffset = true, - ScrollPosition oldPosition, - String debugLabel, - @required this.coordinator}) - : super( + ShopScrollPosition({ + @required ScrollPhysics physics, + @required ScrollContext context, + double initialPixels = 0.0, + bool keepScrollOffset = true, + ScrollPosition oldPosition, + String debugLabel, + @required this.coordinator, + }) : super( physics: physics, context: context, keepScrollOffset: keepScrollOffset, @@ -30,11 +26,19 @@ class ShopScrollPosition extends ScrollPosition debugLabel: debugLabel, ) { // 如果oldPosition不为null,则父级将首先调用Absorb(),它可以设置_pixels和_activity. - if (pixels == null && initialPixels != null) correctPixels(initialPixels); - if (activity == null) goIdle(); + if (pixels == null && initialPixels != null) { + correctPixels(initialPixels); + } + if (activity == null) { + goIdle(); + } assert(activity != null); } + final ShopScrollCoordinator coordinator; // 协调器 + ScrollDragController _currentDrag; + double _heldPreviousVelocity = 0.0; + @override AxisDirection get axisDirection => context.axisDirection; @@ -69,26 +73,29 @@ class ShopScrollPosition extends ScrollPosition } /// 返回未使用的增量。 + /// /// 正增量表示下降(在上方显示内容),负增量向上(在下方显示内容)。 double applyClampedDragUpdate(double delta) { assert(delta != 0.0); - // 如果我们要朝向maxScrollExtent(负滚动偏移),那么我们在minScrollExtent方向上 - // 可以达到的最大距离是负无穷大。 例如,如果我们已经过度滚动,则滚动以减少过度滚动不应禁止过度滚动。 - // 如果我们要朝minScrollExtent(正滚动偏移量)方向移动,那么我们在minScrollExtent方向 - // 上可以达到的最大距离是我们现在所处的位置(如果我们已经过度滚动) - // (在这种情况下,像素小于minScrollExtent),或者如果minScrollExtent可以 我们不是。 - // 换句话说,我们不能通过applyClampedDragUpdate进入过滚动状态。 - // 尽管如此,可能通过多种方式进入了过度滚动的情况。 一种是物理是否允许通过 - // applyFullDragUpdate(请参见下文)。也可能会发生过度滚动的情况,例如 如果使用滚动控制器人工设置了滚动位置。 + // 如果我们要朝向 maxScrollExtent(负滚动偏移),那么我们在 minScrollExtent 方向上 + // 可以达到的最大距离是负无穷大。例如,如果我们已经过度滚动,则滚动以减少过度滚动不应 + // 禁止过度滚动。如果我们要朝 minScrollExtent(正滚动偏移量)方向移动,那么我们在 + // minScrollExtent 方向上可以达到的最大距离是我们现在所处的位置。 + // 换句话说,我们不能通过 applyClampedDragUpdate 进入过滚动状态。 + // 尽管如此,可能通过多种方式进入了过度滚动的情况。一种是物理是否允许通过 + // applyFullDragUpdate(请参见下文)。 + // 可能会发生过度滚动的情况,例如,使用滚动控制器人工设置了滚动位置。 final double min = delta < 0.0 ? -double.infinity : math.min(minScrollExtent, pixels); - // max的逻辑是等效的,但反向。 + // max 的逻辑是等效的,但反向。 final double max = delta > 0.0 ? double.infinity : math.max(maxScrollExtent, pixels); final double oldPixels = pixels; final double newPixels = (pixels - delta).clamp(min, max) as double; final double clampedDelta = newPixels - pixels; - if (clampedDelta == 0.0) return delta; + if (clampedDelta == 0.0) { + return delta; + } final double overScroll = physics.applyBoundaryConditions(this, newPixels); final double actualNewPixels = newPixels - overScroll; final double offset = actualNewPixels - oldPixels; @@ -99,14 +106,17 @@ class ShopScrollPosition extends ScrollPosition return delta + offset; } - // Returns the overScroll. 返回过度滚动。 + // 返回过度滚动。 double applyFullDragUpdate(double delta) { assert(delta != 0.0); final double oldPixels = pixels; // Apply friction: 施加摩擦: final double newPixels = pixels - physics.applyPhysicsToUserOffset(this, delta); - if (oldPixels == newPixels) return 0.0; // 增量一定很小,我们在添加浮点数时将其删除了 + if (oldPixels == newPixels) { + // 增量一定很小,我们在添加浮点数时将其删除了 + return 0.0; + } // Check for overScroll: 检查过度滚动: final double overScroll = physics.applyBoundaryConditions(this, newPixels); final double actualNewPixels = newPixels - overScroll; @@ -117,15 +127,18 @@ class ShopScrollPosition extends ScrollPosition return overScroll; } - /// 当手指滑动时,该方法会获取到滑动距离 - /// [delta]滑动距离,正增量表示下滑,负增量向上滑 - /// 我们需要把子部件的 滑动数据 交给协调器处理,主部件无干扰 + /// 当手指滑动时,该方法会获取到滑动距离。 + /// + /// [delta] 滑动距离,正增量表示下滑,负增量向上滑。 + /// + /// 我们需要把子部件的滑动数据交给协调器处理,主部件无干扰。 @override void applyUserOffset(double delta) { - ScrollDirection userScrollDirection = + final ScrollDirection userScrollDirection = delta > 0.0 ? ScrollDirection.forward : ScrollDirection.reverse; - if (debugLabel != coordinator.pageLabel) + if (debugLabel != coordinator.pageLabel) { return coordinator.applyUserOffset(delta, userScrollDirection, this); + } updateUserScrollDirection(userScrollDirection); setPixels(pixels - physics.applyPhysicsToUserOffset(this, delta)); } @@ -133,21 +146,27 @@ class ShopScrollPosition extends ScrollPosition @override void beginActivity(ScrollActivity newActivity) { _heldPreviousVelocity = 0.0; - if (newActivity == null) return; + if (newActivity == null) { + return; + } assert(newActivity.delegate == this); super.beginActivity(newActivity); _currentDrag?.dispose(); _currentDrag = null; - if (!activity.isScrolling) updateUserScrollDirection(ScrollDirection.idle); + if (!activity.isScrolling) { + updateUserScrollDirection(ScrollDirection.idle); + } } - /// 将[用户滚动方向]设置为给定值。 - /// 如果更改了该值,则将分派[User ScrollNotification]。 + /// 将用户滚动方向设置为给定值。 + /// 如果更改了该值,则将分派 [User ScrollNotification]。 @protected @visibleForTesting void updateUserScrollDirection(ScrollDirection value) { assert(value != null); - if (userScrollDirection == value) return; + if (userScrollDirection == value) { + return; + } _userScrollDirection = value; didUpdateScrollDirection(value); } @@ -155,8 +174,10 @@ class ShopScrollPosition extends ScrollPosition @override ScrollHoldController hold(VoidCallback holdCancelCallback) { final double previousVelocity = activity.velocity; - final HoldScrollActivity holdActivity = - HoldScrollActivity(delegate: this, onHoldCanceled: holdCancelCallback); + final HoldScrollActivity holdActivity = HoldScrollActivity( + delegate: this, + onHoldCanceled: holdCancelCallback, + ); beginActivity(holdActivity); _heldPreviousVelocity = previousVelocity; return holdActivity; @@ -182,17 +203,23 @@ class ShopScrollPosition extends ScrollPosition beginActivity(IdleScrollActivity(this)); } - /// 以特定的速度开始一个物理驱动的模拟,该模拟确定[pixels]位置。 - /// 此方法遵从[ScrollPhysics.createBallisticSimulation],该方法通常在当前位置超出 + /// 以特定的速度开始一个物理驱动的模拟,该模拟确定 [pixels] 位置。 + /// 此方法遵从 [ScrollPhysics.createBallisticSimulation],该方法通常在当前位置超出 /// 范围时提供滑动模拟,而在当前位置超出范围但具有非零速度时提供摩擦模拟。 - /// 速度应以每秒逻辑像素为单位。 + /// 速度应以逻辑像素/秒为单位。 @override void goBallistic(double velocity, [bool fromCoordinator = false]) { if (debugLabel != coordinator.pageLabel) { - if (velocity > 0.0) coordinator.goBallistic(velocity); + if (velocity > 0.0) { + coordinator.goBallistic(velocity); + } } else { - if (fromCoordinator && velocity <= 0.0) return; - if (coordinator.pageExpand == PageExpandState.Expanding) return; + if (fromCoordinator && velocity <= 0.0) { + return; + } + if (coordinator.pageExpand == PageExpandState.Expanding) { + return; + } } assert(pixels != null); final Simulation simulation = diff --git a/pubspec.lock b/pubspec.lock index f2cffeb..5542582 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,62 +1,48 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - archive: - dependency: transitive - description: - name: archive - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.11" - args: - dependency: transitive - description: - name: args - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.5.2" async: dependency: transitive description: name: async url: "https://pub.flutter-io.cn" source: hosted - version: "2.4.0" + version: "2.5.0-nullsafety.1" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.5" - charcode: + version: "2.1.0-nullsafety.1" + characters: dependency: transitive description: - name: charcode + name: characters url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.2" - collection: + version: "1.1.0-nullsafety.3" + charcode: dependency: transitive description: - name: collection + name: charcode url: "https://pub.flutter-io.cn" source: hosted - version: "1.14.11" - convert: + version: "1.2.0-nullsafety.1" + clock: dependency: transitive description: - name: convert + name: clock url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.1" - crypto: + version: "1.1.0-nullsafety.1" + collection: dependency: transitive description: - name: crypto + name: collection url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.3" + version: "1.15.0-nullsafety.3" cupertino_icons: dependency: "direct main" description: @@ -64,6 +50,13 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "0.1.3" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0-nullsafety.1" flutter: dependency: "direct main" description: flutter @@ -74,27 +67,20 @@ packages: description: flutter source: sdk version: "0.0.0" - image: - dependency: transitive - description: - name: image - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.1.4" matcher: dependency: transitive description: name: matcher url: "https://pub.flutter-io.cn" source: hosted - version: "0.12.6" + version: "0.12.10-nullsafety.1" meta: dependency: transitive description: name: meta url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.8" + version: "1.3.0-nullsafety.3" nested: dependency: transitive description: @@ -108,21 +94,7 @@ packages: name: path url: "https://pub.flutter-io.cn" source: hosted - version: "1.6.4" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.8.0+1" - petitparser: - dependency: transitive - description: - name: petitparser - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.4.0" + version: "1.8.0-nullsafety.1" provider: dependency: "direct main" description: @@ -130,13 +102,6 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "4.0.2" - quiver: - dependency: transitive - description: - name: quiver - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.5" sky_engine: dependency: transitive description: flutter @@ -148,63 +113,56 @@ packages: name: source_span url: "https://pub.flutter-io.cn" source: hosted - version: "1.5.5" + version: "1.8.0-nullsafety.2" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.flutter-io.cn" source: hosted - version: "1.9.3" + version: "1.10.0-nullsafety.1" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.0" + version: "2.1.0-nullsafety.1" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.5" + version: "1.1.0-nullsafety.1" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.0" + version: "1.2.0-nullsafety.1" test_api: dependency: transitive description: name: test_api url: "https://pub.flutter-io.cn" source: hosted - version: "0.2.11" + version: "0.2.19-nullsafety.2" typed_data: dependency: transitive description: name: typed_data url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.6" + version: "1.3.0-nullsafety.3" vector_math: dependency: transitive description: name: vector_math url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.8" - xml: - dependency: transitive - description: - name: xml - url: "https://pub.flutter-io.cn" - source: hosted - version: "3.5.0" + version: "2.1.0-nullsafety.3" sdks: - dart: ">=2.6.0 <3.0.0" + dart: ">=2.10.0-110 <2.11.0" flutter: ">=1.12.1"