import 'dart:math' as math;
import 'package:flutter/gestures.dart';
import 'package:flutter/physics.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'customScrollCoordinator.dart';
/// 滑动位置信息
class CustomScrollPosition extends ScrollPosition
implements ScrollActivityDelegate {
CustomScrollPosition({
@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,
oldPosition: oldPosition,
debugLabel: debugLabel,
) {
// 如果oldPosition不为null,则父级将首先调用Absorb(),它可以设置_pixels和_activity.
if (pixels == null && initialPixels != null) {
correctPixels(initialPixels);
}
if (activity == null) {
goIdle();
}
assert(activity != null);
}
final CustomScrollCoordinator coordinator; // 协调器
ScrollDragController _currentDrag;
double _heldPreviousVelocity = 0.0;
@override
AxisDirection get axisDirection => context.axisDirection;
@override
double setPixels(double newPixels) {
assert(activity.isScrolling);
return super.setPixels(newPixels);
}
@override
void absorb(ScrollPosition other) {
super.absorb(other);
if (other is! CustomScrollPosition) {
goIdle();
return;
}
activity.updateDelegate(this);
final CustomScrollPosition typedOther = other as CustomScrollPosition;
_userScrollDirection = typedOther._userScrollDirection;
assert(_currentDrag == null);
if (typedOther._currentDrag != null) {
_currentDrag = typedOther._currentDrag;
_currentDrag.updateDelegate(this);
typedOther._currentDrag = null;
}
}
@override
void applyNewDimensions() {
super.applyNewDimensions();
context.setCanDrag(physics.shouldAcceptUserOffset(this));
}
/// 返回未使用的增量。
///
/// 正增量表示下降(在上方显示内容),负增量向上(在下方显示内容)。
double applyClampedDragUpdate(double delta) {
assert(delta != 0.0);
// 如果我们要朝向 maxScrollExtent(负滚动偏移),那么我们在 minScrollExtent 方向上
// 可以达到的最大距离是负无穷大。例如,如果我们已经过度滚动,则滚动以减少过度滚动不应
// 禁止过度滚动。如果我们要朝 minScrollExtent(正滚动偏移量)方向移动,那么我们在
// minScrollExtent 方向上可以达到的最大距离是我们现在所处的位置。
// 换句话说,我们不能通过 applyClampedDragUpdate 进入过滚动状态。
// 尽管如此,可能通过多种方式进入了过度滚动的情况。一种是物理是否允许通过
// applyFullDragUpdate(请参见下文)。
// 可能会发生过度滚动的情况,例如,使用滚动控制器人工设置了滚动位置。
final double min =
delta < 0.0 ? -double.infinity : math.min(minScrollExtent, pixels);
// 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;
}
final double overScroll = physics.applyBoundaryConditions(this, newPixels);
final double actualNewPixels = newPixels - overScroll;
final double offset = actualNewPixels - oldPixels;
if (offset != 0.0) {
forcePixels(actualNewPixels);
didUpdateScrollPositionBy(offset);
}
return delta + offset;
}
// 返回过度滚动。
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;
}
// Check for overScroll: 检查过度滚动:
final double overScroll = physics.applyBoundaryConditions(this, newPixels);
final double actualNewPixels = newPixels - overScroll;
if (actualNewPixels != oldPixels) {
forcePixels(actualNewPixels);
didUpdateScrollPositionBy(actualNewPixels - oldPixels);
}
return overScroll;
}
@override
void beginActivity(ScrollActivity newActivity) {
_heldPreviousVelocity = 0.0;
if (newActivity == null) {
return;
}
assert(newActivity.delegate == this);
super.beginActivity(newActivity);
_currentDrag?.dispose();
_currentDrag = null;
if (!activity.isScrolling) {
updateUserScrollDirection(ScrollDirection.idle);
}else{
}
}
/// 将用户滚动方向设置为给定值。
/// 如果更改了该值,则将分派 [User ScrollNotification]。
@protected
@visibleForTesting
void updateUserScrollDirection(ScrollDirection value) {
assert(value != null);
if (userScrollDirection == value) {
return;
}
_userScrollDirection = value;
didUpdateScrollDirection(value);
}
@override
ScrollHoldController hold(VoidCallback holdCancelCallback) {
final double previousVelocity = activity.velocity;
final HoldScrollActivity holdActivity = HoldScrollActivity(
delegate: this,
onHoldCanceled: holdCancelCallback,
);
beginActivity(holdActivity);
_heldPreviousVelocity = previousVelocity;
return holdActivity;
}
@override
Drag drag(DragStartDetails details, VoidCallback dragCancelCallback) {
final ScrollDragController drag = ScrollDragController(
delegate: this,
details: details,
onDragCanceled: dragCancelCallback,
carriedVelocity: physics.carriedMomentum(_heldPreviousVelocity),
motionStartDistanceThreshold: physics.dragStartDistanceMotionThreshold,
);
beginActivity(DragScrollActivity(this, drag));
assert(_currentDrag == null);
_currentDrag = drag;
return drag;
}
@override
void goIdle() {
double velocity = 0;
if(activity != null) {
if (debugLabel == coordinator.debugLabel) {
//主滚动结束,但是有剩余速度
if (activity.velocity != 0) {
velocity = activity.velocity;
}
} else {
if (activity.velocity != 0) {
velocity = activity.velocity;
}
}
}
beginActivity(IdleScrollActivity(this));
if(velocity != 0){
if(debugLabel == coordinator.debugLabel){
// print('主list滚动结束-剩余转子list滚动:$velocity');
coordinator.goBallistic(velocity,scrollInner: true);
}else{
// print('子list滚动结束-剩余转主list滚动');
coordinator.goBallistic(velocity);
}
}
}
/// 当手指滑动时,该方法会获取到滑动距离。
///
/// [delta] 滑动距离,正增量表示下滑,负增量向上滑。
///
/// 我们需要把子部件的滑动数据交给协调器处理,主部件无干扰。
@override
void applyUserOffset(double delta) {
coordinator.coordinatorScrolling();
final ScrollDirection userScrollDirection = delta > 0.0 ? ScrollDirection.forward : ScrollDirection.reverse;
bool listviewAtTop = pixels == 0;
if (debugLabel != coordinator.debugLabel) {
//内部滚动
if(userScrollDirection == ScrollDirection.reverse){
//用户向上滑动
return coordinator.applyUserOffset(delta, userScrollDirection, this);
}else{
//用户向下滑动
if(listviewAtTop){
return coordinator.applyUserOffset(delta, userScrollDirection, this);
}
}
}
updateUserScrollDirection(userScr
没有合适的资源?快使用搜索试试~ 我知道了~
flutter页面滚动联动实现
共3个文件
dart:3个
5星 · 超过95%的资源 需积分: 20 7 下载量 29 浏览量
2022-03-25
19:44:30
上传
评论
收藏 9KB ZIP 举报
温馨提示
flutter 页面滚动联动实现,解决NestedScrollView问题.可配合EasyRefresh和CustomScrollView实现页面滚动联动,自定义下拉刷新等操作
资源详情
资源评论
资源推荐
收起资源包目录
customScrollController.zip (3个子文件)
customScrollController
customScrollPosition.dart 11KB
customScrollCoordinator.dart 4KB
customScrollController.dart 9KB
共 3 条
- 1
ant1239
- 粉丝: 25
- 资源: 5
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论10