53 lines
1.6 KiB
Dart
53 lines
1.6 KiB
Dart
// Author: fruit.com.cn
|
|
// 职责:协调首页三页的点击动画、最终选中目标和手势中断。
|
|
import 'package:flutter/widgets.dart';
|
|
|
|
const _transitionDuration = Duration(milliseconds: 220);
|
|
|
|
/// 页面移动时保留用户最终目标,防止跨页动画途中的页面抢占高亮。
|
|
class HomeTabMotionController extends PageController {
|
|
/// [onSettled] 在动画结束或被手势中断时同步实际停留页面。
|
|
HomeTabMotionController({required this.onSettled});
|
|
|
|
final ValueChanged<int> onSettled;
|
|
int? _target;
|
|
int _revision = 0;
|
|
bool _disposed = false;
|
|
|
|
/// 供导航绘制连续位置;布局尚未建立时使用初始页。
|
|
double get pagePosition => hasClients && position.hasContentDimensions
|
|
? page ?? initialPage.toDouble()
|
|
: initialPage.toDouble();
|
|
|
|
/// 点击跨页过程中只接受最终目标;拖动和稳定状态接受实际页。
|
|
bool acceptsSelection(int index) => _target == null || _target == index;
|
|
|
|
/// 点击导航时平滑移动;系统减少动画时直接到位。
|
|
Future<void> selectPage(int index, {required bool reduceMotion}) async {
|
|
final revision = ++_revision;
|
|
_target = index;
|
|
if (!hasClients) {
|
|
_target = null;
|
|
return;
|
|
}
|
|
if (reduceMotion) {
|
|
jumpToPage(index);
|
|
} else {
|
|
await animateToPage(
|
|
index,
|
|
duration: _transitionDuration,
|
|
curve: Curves.easeOut,
|
|
);
|
|
}
|
|
if (_disposed || revision != _revision) return;
|
|
_target = null;
|
|
if (hasClients) onSettled(pagePosition.round());
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_disposed = true;
|
|
super.dispose();
|
|
}
|
|
}
|