applyBoundaryConditions method
应用边界条件到滚动位置
该方法用于控制滚动位置的边界条件,防止滚动超出允许的范围
参数:
position:当前滚动位置value:期望的滚动位置- 返回值:需要调整的偏移量,如果不需要调整则返回0.0
Implementation
@override
/// 应用边界条件到滚动位置
///
/// 该方法用于控制滚动位置的边界条件,防止滚动超出允许的范围
///
/// 参数:
/// - [position]:当前滚动位置
/// - [value]:期望的滚动位置
/// - 返回值:需要调整的偏移量,如果不需要调整则返回0.0
double applyBoundaryConditions(ScrollMetrics position, double value) {
final ScrollPosition scrollPosition = position as ScrollPosition;
viewportRender ??= findViewport(controller!.position?.context.storageContext);
// 检查内容是否不满一屏
final bool isContentNotFull = position.minScrollExtent == position.maxScrollExtent;
// 检查是否启用了下拉刷新和上拉加载
final bool enablePullDown = viewportRender == null ? false : viewportRender!.firstChild is RenderSliverRefresh;
final bool enablePullUp = viewportRender == null ? false : viewportRender!.lastChild is RenderSliverLoading;
// 检查是否启用了对应方向的刷新
if ((position.pixels - value > 0.0 && !enablePullDown) || (position.pixels - value < 0 && !enablePullUp)) {
return parent!.applyBoundaryConditions(position, value);
}
// 计算顶部和底部的额外空间
double topExtra = 0.0;
double bottomExtra = 0.0;
// 计算顶部额外空间(下拉刷新时)
if (enablePullDown) {
final RenderSliverRefresh sliverHeader = viewportRender!.firstChild as RenderSliverRefresh;
topExtra = sliverHeader.hasLayoutExtent ? 0.0 : sliverHeader.refreshIndicatorLayoutExtent;
}
// 计算底部额外空间(上拉加载时)
if (enablePullUp) {
final RenderSliverLoading? sliverFooter = viewportRender!.lastChild as RenderSliverLoading?;
bool shouldHideFooter = false;
// 检查是否需要隐藏底部加载组件
if (!isContentNotFull && sliverFooter!.geometry!.scrollExtent != 0) {
shouldHideFooter = true;
} else if (isContentNotFull) {
// 内容不满一屏时的处理
final refreshConfig = RefreshConfiguration.of(controller!.position!.context.storageContext);
if (controller!.footerStatus == LoadStatus.noMore && !refreshConfig!.enableLoadingWhenNoData) {
shouldHideFooter = true;
} else if (refreshConfig?.hideFooterWhenNotFull ?? false) {
shouldHideFooter = true;
}
}
bottomExtra = shouldHideFooter ? 0.0 : (sliverFooter!.layoutExtent ?? 0.0);
}
// 计算最终的边界位置
final double topBoundary = position.minScrollExtent - (maxOverScrollExtent ?? 0.0) - topExtra;
final double bottomBoundary = position.maxScrollExtent + (maxUnderScrollExtent ?? 0.0) + bottomExtra;
// 处理弹道滚动(惯性滚动)的边界条件
if (scrollPosition.activity is BallisticScrollActivity) {
// 处理顶部碰撞边界
if (topHitBoundary != null && topHitBoundary != double.infinity) {
if (value < -topHitBoundary! && -topHitBoundary! <= position.pixels) {
// 碰到顶部边缘
return value + topHitBoundary!;
}
}
// 处理底部碰撞边界
if (bottomHitBoundary != null && bottomHitBoundary != double.infinity) {
if (position.pixels < bottomHitBoundary! + position.maxScrollExtent &&
bottomHitBoundary! + position.maxScrollExtent < value) {
// 碰到底部边缘
return value - bottomHitBoundary! - position.maxScrollExtent;
}
}
}
// 处理超出顶部边界的情况
if (maxOverScrollExtent != null &&
maxOverScrollExtent != double.infinity &&
value < topBoundary &&
topBoundary < position.pixels) {
// 碰到顶部边缘
return value - topBoundary;
}
// 处理超出底部边界的情况
if (maxUnderScrollExtent != null &&
maxUnderScrollExtent != double.infinity &&
position.pixels < bottomBoundary &&
bottomBoundary < value) {
// 碰到底部边缘
return value - bottomBoundary;
}
// 处理用户拖动时的边界条件
// 这很重要,因为不同设备在不同帧和时间可能有不同的弹跳行为,导致返回不同的速度
if (scrollPosition.activity is DragScrollActivity) {
// 处理上拉超出顶部边界的情况
if (maxOverScrollExtent != null &&
maxOverScrollExtent != double.infinity &&
value < position.pixels &&
position.pixels <= topBoundary) {
// 上拉超出范围
return value - position.pixels;
}
// 处理下拉超出底部边界的情况
if (maxUnderScrollExtent != null &&
maxUnderScrollExtent != double.infinity &&
bottomBoundary <= position.pixels &&
position.pixels < value) {
// 下拉超出范围
return value - position.pixels;
}
}
// 不需要调整
return 0.0;
}