75 lines
1.6 KiB
Dart
75 lines
1.6 KiB
Dart
// lib/widgets/magnetic_scroll_physics.dart
|
|
import 'package:flutter/material.dart';
|
|
|
|
class MagneticScrollPhysics extends ClampingScrollPhysics {
|
|
final double snapPoint;
|
|
final double magneticZoneStart;
|
|
|
|
const MagneticScrollPhysics({
|
|
required this.snapPoint,
|
|
this.magneticZoneStart = 0.20,
|
|
super.parent,
|
|
});
|
|
|
|
@override
|
|
MagneticScrollPhysics applyTo(ScrollPhysics? ancestor) {
|
|
return MagneticScrollPhysics(
|
|
snapPoint: snapPoint,
|
|
magneticZoneStart: magneticZoneStart,
|
|
parent: buildParent(ancestor),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Simulation? createBallisticSimulation(
|
|
ScrollMetrics position,
|
|
double velocity,
|
|
) {
|
|
final offset = position.pixels;
|
|
|
|
if (offset <= 0 || offset >= snapPoint) {
|
|
return super.createBallisticSimulation(position, velocity);
|
|
}
|
|
|
|
final shouldSnap = _shouldSnap(offset, velocity);
|
|
|
|
final target = shouldSnap ? snapPoint : 0.0;
|
|
|
|
if ((offset - target).abs() < 1.0) {
|
|
return null;
|
|
}
|
|
|
|
return ScrollSpringSimulation(
|
|
SpringDescription(
|
|
mass: 1.0,
|
|
stiffness: 320.0,
|
|
damping: 26.0,
|
|
),
|
|
offset,
|
|
target,
|
|
velocity,
|
|
tolerance: const Tolerance(
|
|
velocity: 0.01,
|
|
distance: 0.5,
|
|
),
|
|
);
|
|
}
|
|
|
|
bool _shouldSnap(double offset, double velocity) {
|
|
final zoneStart = snapPoint * magneticZoneStart;
|
|
|
|
// 向上滑 → 吸附展开
|
|
if (velocity > 20) {
|
|
return true;
|
|
}
|
|
|
|
// 向下滑 → 回去
|
|
if (velocity < -20) {
|
|
return false;
|
|
}
|
|
|
|
// 松手速度很小,用当前位置决定
|
|
return offset >= zoneStart;
|
|
}
|
|
}
|