Improve animation

This commit is contained in:
2025-01-29 20:52:37 +08:00
parent 3e5ae0a39a
commit a3e758831b
2 changed files with 161 additions and 102 deletions

View File

@@ -20,6 +20,7 @@ class AppPageRoute<T> extends PageRoute<T> with _AppRouteTransitionMixin {
super.barrierDismissible = false,
this.enableIOSGesture = true,
this.preventRebuild = true,
this.isRoot = false,
}) {
assert(opaque);
}
@@ -44,6 +45,9 @@ class AppPageRoute<T> extends PageRoute<T> with _AppRouteTransitionMixin {
@override
final bool preventRebuild;
@override
final bool isRoot;
static void updateBackButton() {
Future.delayed(const Duration(milliseconds: 300), () {
StateController.findOrNull(tag: "back_button")?.update();
@@ -77,6 +81,8 @@ mixin _AppRouteTransitionMixin<T> on PageRoute<T> {
Widget? _child;
bool get isRoot;
@override
Widget buildPage(
BuildContext context,
@@ -115,6 +121,22 @@ mixin _AppRouteTransitionMixin<T> on PageRoute<T> {
@override
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
if (isRoot) {
return EntrancePageTransition(
animation: CurvedAnimation(
parent: animation,
curve: FluentTheme.of(context).animationCurve,
),
child: enableIOSGesture && App.isIOS
? IOSBackGestureDetector(
gestureWidth: _kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(this),
onStartPopGesture: () => _startPopGesture(this),
child: child)
: child,
);
}
return DrillInPageTransition(
animation: CurvedAnimation(
parent: animation,
@@ -388,3 +410,35 @@ class SideBarRoute<T> extends PopupRoute<T> {
return IOSBackGestureController(route.controller!, route.navigator!);
}
}
class EntrancePageTransition extends StatelessWidget {
/// Creates an entrance page transition
const EntrancePageTransition({
super.key,
required this.child,
required this.animation,
});
/// The widget to be animated
final Widget child;
/// The animation to drive this transition
final Animation<double> animation;
@override
Widget build(BuildContext context) {
return ColoredBox(
color: FluentTheme.of(context).micaBackgroundColor,
child: SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 0.1),
end: Offset.zero,
).animate(animation),
child: FadeTransition(
opacity: animation,
child: child,
),
),
);
}
}

View File

@@ -132,112 +132,112 @@ class _MainPageState extends State<MainPage>
return DefaultSelectionStyle.merge(
selectionColor: FluentTheme.of(context).selectionColor.toOpacity(0.4),
child: NavigationView(
appBar: buildAppBar(context, navigatorKey),
pane: NavigationPane(
selected: index,
onChanged: (value) {
setState(() {
index = value;
});
navigate(value);
},
items: [
UserPane(),
PaneItem(
icon: const Icon(
MdIcons.search,
size: 20,
),
title: Text('Search'.tl),
body: const SizedBox.shrink(),
appBar: buildAppBar(context, navigatorKey),
pane: NavigationPane(
selected: index,
onChanged: (value) {
setState(() {
index = value;
});
navigate(value);
},
items: [
UserPane(),
PaneItem(
icon: const Icon(
MdIcons.search,
size: 20,
),
PaneItem(
icon: const Icon(
MdIcons.downloading,
size: 20,
),
title: Text('Downloading'.tl),
body: const SizedBox.shrink(),
title: Text('Search'.tl),
body: const SizedBox.shrink(),
),
PaneItem(
icon: const Icon(
MdIcons.downloading,
size: 20,
),
PaneItem(
icon: const Icon(
MdIcons.download,
size: 20,
),
title: Text('Downloaded'.tl),
body: const SizedBox.shrink(),
title: Text('Downloading'.tl),
body: const SizedBox.shrink(),
),
PaneItem(
icon: const Icon(
MdIcons.download,
size: 20,
),
PaneItemSeparator(),
PaneItemHeader(
header: Text('${"Illustrations".tl}/${"Manga".tl}')
.paddingBottom(4)
.paddingLeft(8)),
PaneItem(
icon: const Icon(
MdIcons.explore_outlined,
size: 20,
),
title: Text('Explore'.tl),
body: const SizedBox.shrink(),
title: Text('Downloaded'.tl),
body: const SizedBox.shrink(),
),
PaneItemSeparator(),
PaneItemHeader(
header: Text('${"Illustrations".tl}/${"Manga".tl}')
.paddingBottom(4)
.paddingLeft(8)),
PaneItem(
icon: const Icon(
MdIcons.explore_outlined,
size: 20,
),
PaneItem(
icon: const Icon(MdIcons.bookmark_outline, size: 20),
title: Text('Bookmarks'.tl),
body: const SizedBox.shrink(),
),
PaneItem(
icon: const Icon(MdIcons.interests_outlined, size: 20),
title: Text('Following'.tl),
body: const SizedBox.shrink(),
),
PaneItem(
icon: const Icon(MdIcons.history, size: 20),
title: Text('History'.tl),
body: const SizedBox.shrink(),
),
PaneItem(
icon: const Icon(MdIcons.leaderboard_outlined, size: 20),
title: Text('Ranking'.tl),
body: const SizedBox.shrink(),
),
PaneItemSeparator(),
PaneItemHeader(
header: Text("Novel".tl).paddingBottom(4).paddingLeft(8)),
PaneItem(
icon: const Icon(MdIcons.featured_play_list_outlined, size: 20),
title: Text('Recommendation'.tl),
body: const SizedBox.shrink(),
),
PaneItem(
icon:
const Icon(MdIcons.collections_bookmark_outlined, size: 20),
title: Text('Bookmarks'.tl),
body: const SizedBox.shrink(),
),
PaneItem(
icon: const Icon(MdIcons.leaderboard_outlined, size: 20),
title: Text('Ranking'.tl),
body: const SizedBox.shrink(),
),
PaneItemSeparator(),
PaneItem(
icon: const Icon(MdIcons.settings_outlined, size: 20),
title: Text('Settings'.tl),
body: const SizedBox.shrink(),
),
],
title: Text('Explore'.tl),
body: const SizedBox.shrink(),
),
PaneItem(
icon: const Icon(MdIcons.bookmark_outline, size: 20),
title: Text('Bookmarks'.tl),
body: const SizedBox.shrink(),
),
PaneItem(
icon: const Icon(MdIcons.interests_outlined, size: 20),
title: Text('Following'.tl),
body: const SizedBox.shrink(),
),
PaneItem(
icon: const Icon(MdIcons.history, size: 20),
title: Text('History'.tl),
body: const SizedBox.shrink(),
),
PaneItem(
icon: const Icon(MdIcons.leaderboard_outlined, size: 20),
title: Text('Ranking'.tl),
body: const SizedBox.shrink(),
),
PaneItemSeparator(),
PaneItemHeader(
header: Text("Novel".tl).paddingBottom(4).paddingLeft(8)),
PaneItem(
icon: const Icon(MdIcons.featured_play_list_outlined, size: 20),
title: Text('Recommendation'.tl),
body: const SizedBox.shrink(),
),
PaneItem(
icon: const Icon(MdIcons.collections_bookmark_outlined, size: 20),
title: Text('Bookmarks'.tl),
body: const SizedBox.shrink(),
),
PaneItem(
icon: const Icon(MdIcons.leaderboard_outlined, size: 20),
title: Text('Ranking'.tl),
body: const SizedBox.shrink(),
),
PaneItemSeparator(),
PaneItem(
icon: const Icon(MdIcons.settings_outlined, size: 20),
title: Text('Settings'.tl),
body: const SizedBox.shrink(),
),
],
),
paneBodyBuilder: (pane, child) => MediaQuery.removePadding(
context: context,
removeTop: true,
child: Navigator(
key: navigatorKey,
onGenerateRoute: (settings) => AppPageRoute(
isRoot: true,
builder: (context) => pageBuilders.elementAtOrNull(index)!(),
),
),
paneBodyBuilder: (pane, child) => MediaQuery.removePadding(
context: context,
removeTop: true,
child: Navigator(
key: navigatorKey,
onGenerateRoute: (settings) => AppPageRoute(
builder: (context) =>
pageBuilders.elementAtOrNull(index)!(),
),
),
)),
),
),
);
}
@@ -263,7 +263,12 @@ class _MainPageState extends State<MainPage>
child: Text("Invalid Page: $index"),
);
navigatorKey.currentState!.pushAndRemoveUntil(
AppPageRoute(builder: (context) => page()), (route) => false);
AppPageRoute(
builder: (context) => page(),
isRoot: true,
),
(route) => false,
);
}
NavigationAppBar buildAppBar(