fix(flutter): 修复下拉刷新页面跟随

This commit is contained in:
Zhou Weidong committed 2026-10-20 16:57:28 +08:00
1 parent c4dcb714ab
commit 69eaacd74f
16 files changed
+85 -34

No files matched your search

+40 -2
View File
@@ -9,6 +9,8 @@ import '../theme/app_colors.dart';
const double _maxPullDistance = 96;
const double _refreshThreshold = 56;
const double _indicatorHeight = 64;
const double _indicatorMaxOffset = 10;
const Duration _arrowTurnDuration = Duration(milliseconds: 160);
const Duration _retractDuration = Duration(milliseconds: 200);
@@ -23,6 +25,9 @@ class AppPullToRefresh extends StatefulWidget {
this.edgeOffset = 0,
});
static const AlwaysScrollableScrollPhysics physics =
AlwaysScrollableScrollPhysics(parent: BouncingScrollPhysics());
final Widget child;
final Future<void> Function() onRefresh;
final double edgeOffset;
@@ -40,6 +45,12 @@ class _AppPullToRefreshState extends State<AppPullToRefresh> {
if (notification.depth != 0 || _refreshing) return false;
if (notification is ScrollStartNotification) {
if (notification.dragDetails != null) _setPullDistance(0);
} else if (notification is ScrollUpdateNotification) {
if (notification.dragDetails != null) {
_setPullDistance(
notification.metrics.minScrollExtent - notification.metrics.pixels,
);
}
} else if (notification is OverscrollNotification) {
if (notification.dragDetails != null) {
_setPullDistance(_pullDistance - notification.overscroll);
@@ -100,19 +111,46 @@ class _AppPullToRefreshState extends State<AppPullToRefresh> {
child: Stack(
fit: StackFit.expand,
children: [
widget.child,
Listener(
onPointerUp: (_) => _release(),
onPointerCancel: (_) => _release(),
child: widget.child,
),
if (_state != _PullState.idle)
Positioned(
top: widget.edgeOffset,
left: 0,
right: 0,
child: IgnorePointer(child: _indicator(context)),
child: IgnorePointer(child: _indicatorLayer(context)),
),
],
),
);
}
Widget _indicatorLayer(BuildContext context) {
final progress = (_pullDistance / _refreshThreshold).clamp(0.0, 1.0);
final opacity = _state == _PullState.refreshing
? 1.0
: progress.clamp(0.0, 1.0);
return SizedBox(
height: _indicatorHeight,
child: Opacity(
opacity: opacity,
child: Transform.translate(
offset: Offset(0, _indicatorMaxOffset * progress),
child: Align(
alignment: Alignment.topCenter,
child: Padding(
padding: const EdgeInsets.only(top: 8),
child: _indicator(context),
),
),
),
),
);
}
Widget _indicator(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
if (_state == _PullState.refreshing) {