240 lines
7.0 KiB
Dart
240 lines
7.0 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:get/get.dart';
|
||
|
||
enum SlideDirection { leftToRight, rightToLeft }
|
||
|
||
/// 智能转场类,根据路由上下文决定转场方向
|
||
class ContextAwareSlideTransition extends CustomTransition {
|
||
final String targetRoute;
|
||
final Duration duration;
|
||
|
||
ContextAwareSlideTransition({
|
||
required this.targetRoute,
|
||
this.duration = const Duration(milliseconds: 350),
|
||
});
|
||
|
||
@override
|
||
Widget buildTransition(
|
||
BuildContext context,
|
||
Curve? curve,
|
||
Alignment? alignment,
|
||
Animation<double> animation,
|
||
Animation<double> secondaryAnimation,
|
||
Widget child) {
|
||
|
||
// 获取当前路由信息
|
||
final currentRoute = Get.currentRoute;
|
||
final previousRoute = Get.previousRoute;
|
||
|
||
// 决定转场方向
|
||
SlideDirection direction = _determineDirection(currentRoute, previousRoute);
|
||
|
||
// 确保移动距离一致:都是1.0个屏幕宽度
|
||
const double slideDistance = 1.0;
|
||
|
||
// 新页面入场方向
|
||
final newPageBeginOffset = direction == SlideDirection.rightToLeft
|
||
? Offset(slideDistance, 0)
|
||
: Offset(-slideDistance, 0);
|
||
|
||
// 旧页面滑出方向(与新页面相反,距离相同)
|
||
final oldPageEndOffset = direction == SlideDirection.rightToLeft
|
||
? Offset(-slideDistance, 0)
|
||
: Offset(slideDistance, 0);
|
||
|
||
// 使用相同的动画曲线确保同步
|
||
final animationCurve = curve ?? Curves.elasticOut;
|
||
|
||
// 新页面滑入动画:从屏幕外滑入到中心
|
||
final newPageAnimation = Tween<Offset>(
|
||
begin: newPageBeginOffset,
|
||
end: Offset.zero,
|
||
).animate(CurvedAnimation(
|
||
parent: animation,
|
||
curve: animationCurve,
|
||
));
|
||
|
||
// 旧页面滑出动画:从中心滑出到屏幕外
|
||
final oldPageAnimation = Tween<Offset>(
|
||
begin: Offset.zero,
|
||
end: oldPageEndOffset,
|
||
).animate(CurvedAnimation(
|
||
parent: secondaryAnimation,
|
||
curve: animationCurve,
|
||
));
|
||
|
||
// 使用 AnimatedBuilder 来监听 secondaryAnimation 的变化
|
||
return AnimatedBuilder(
|
||
animation: secondaryAnimation,
|
||
builder: (context, _) {
|
||
// 如果 secondaryAnimation 正在运行,说明这是旧页面
|
||
if (secondaryAnimation.status == AnimationStatus.forward ||
|
||
secondaryAnimation.status == AnimationStatus.reverse) {
|
||
return SlideTransition(
|
||
position: oldPageAnimation,
|
||
child: child,
|
||
);
|
||
}
|
||
|
||
// 否则这是新页面
|
||
return SlideTransition(
|
||
position: newPageAnimation,
|
||
child: child,
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
/// 根据路由上下文决定转场方向
|
||
SlideDirection _determineDirection(String currentRoute, String previousRoute) {
|
||
// 如果目标路由是 HI_MENU
|
||
if (targetRoute == '/hi_menu') {
|
||
// 从 home 页面来的,使用左到右(menu 从左侧进入)
|
||
if (previousRoute == '/kr_home' || previousRoute.contains('kr_home')) {
|
||
return SlideDirection.leftToRight;
|
||
}
|
||
// 去其他页面,使用右到左
|
||
else {
|
||
return SlideDirection.rightToLeft;
|
||
}
|
||
}
|
||
|
||
// 默认使用右到左
|
||
return SlideDirection.rightToLeft;
|
||
}
|
||
}
|
||
|
||
class SlideTransparentTransition extends CustomTransition {
|
||
final SlideDirection direction;
|
||
final Duration duration;
|
||
|
||
SlideTransparentTransition({
|
||
this.direction = SlideDirection.rightToLeft,
|
||
this.duration = const Duration(milliseconds: 1000),
|
||
});
|
||
|
||
@override
|
||
Widget buildTransition(
|
||
BuildContext context,
|
||
Curve? curve,
|
||
Alignment? alignment,
|
||
Animation<double> animation,
|
||
Animation<double> secondaryAnimation,
|
||
Widget child) {
|
||
|
||
// 确保移动距离一致:都是1.0个屏幕宽度
|
||
const double slideDistance = 1.0;
|
||
|
||
// 新页面入场方向
|
||
final newPageBeginOffset = direction == SlideDirection.rightToLeft
|
||
? Offset(slideDistance, 0)
|
||
: Offset(-slideDistance, 0);
|
||
|
||
// 旧页面滑出方向(与新页面相反,距离相同)
|
||
final oldPageEndOffset = direction == SlideDirection.rightToLeft
|
||
? Offset(-slideDistance, 0)
|
||
: Offset(slideDistance, 0);
|
||
|
||
// 使用相同的动画曲线确保同步
|
||
final animationCurve = curve ?? Curves.elasticOut;
|
||
|
||
// 新页面滑入动画:从屏幕外滑入到中心
|
||
final newPageAnimation = Tween<Offset>(
|
||
begin: newPageBeginOffset,
|
||
end: Offset.zero,
|
||
).animate(CurvedAnimation(
|
||
parent: animation,
|
||
curve: animationCurve,
|
||
));
|
||
|
||
// 旧页面滑出动画:从中心滑出到屏幕外
|
||
final oldPageAnimation = Tween<Offset>(
|
||
begin: Offset.zero,
|
||
end: oldPageEndOffset,
|
||
).animate(CurvedAnimation(
|
||
parent: secondaryAnimation,
|
||
curve: animationCurve,
|
||
));
|
||
|
||
// 使用 AnimatedBuilder 来监听 secondaryAnimation 的变化
|
||
return AnimatedBuilder(
|
||
animation: secondaryAnimation,
|
||
builder: (context, _) {
|
||
// 如果 secondaryAnimation 正在运行,说明这是旧页面
|
||
if (secondaryAnimation.status == AnimationStatus.forward ||
|
||
secondaryAnimation.status == AnimationStatus.reverse) {
|
||
return SlideTransition(
|
||
position: oldPageAnimation,
|
||
child: child,
|
||
);
|
||
}
|
||
|
||
// 否则这是新页面
|
||
return SlideTransition(
|
||
position: newPageAnimation,
|
||
child: child,
|
||
);
|
||
},
|
||
);
|
||
}
|
||
}
|
||
|
||
class SlideOutOnlyTransition extends CustomTransition {
|
||
final SlideDirection direction;
|
||
final Duration duration;
|
||
|
||
SlideOutOnlyTransition({
|
||
this.direction = SlideDirection.rightToLeft,
|
||
this.duration = const Duration(milliseconds: 350),
|
||
});
|
||
|
||
@override
|
||
Widget buildTransition(
|
||
BuildContext context,
|
||
Curve? curve,
|
||
Alignment? alignment,
|
||
Animation<double> animation,
|
||
Animation<double> secondaryAnimation,
|
||
Widget child) {
|
||
|
||
const double slideDistance = 1.0;
|
||
|
||
// 旧页面出场动画
|
||
final oldPageEndOffset = direction == SlideDirection.rightToLeft
|
||
? Offset(-slideDistance, 0)
|
||
: Offset(slideDistance, 0);
|
||
|
||
final oldPageAnimation = Tween<Offset>(
|
||
begin: Offset.zero,
|
||
end: oldPageEndOffset,
|
||
).animate(CurvedAnimation(
|
||
parent: secondaryAnimation,
|
||
curve: curve ?? Curves.easeOut,
|
||
));
|
||
|
||
// 新页面入场无动画
|
||
final newPageAnimation = Tween<Offset>(
|
||
begin: Offset.zero,
|
||
end: Offset.zero,
|
||
).animate(animation);
|
||
|
||
return AnimatedBuilder(
|
||
animation: secondaryAnimation,
|
||
builder: (context, _) {
|
||
// secondaryAnimation 正在执行,表示旧页面在出场
|
||
if (secondaryAnimation.status == AnimationStatus.forward ||
|
||
secondaryAnimation.status == AnimationStatus.reverse) {
|
||
return SlideTransition(
|
||
position: oldPageAnimation,
|
||
child: child,
|
||
);
|
||
}
|
||
// 否则新页面直接显示,无动画
|
||
return SlideTransition(
|
||
position: newPageAnimation,
|
||
child: child,
|
||
);
|
||
},
|
||
);
|
||
}
|
||
} |