mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
Change page transition animation for Android.
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
|
android:enableOnBackInvokedCallback="true"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||||
the Android process has started. This theme is visible to the user
|
the Android process has started. This theme is visible to the user
|
||||||
|
@@ -7,8 +7,11 @@ class PaneItemEntry {
|
|||||||
|
|
||||||
IconData activeIcon;
|
IconData activeIcon;
|
||||||
|
|
||||||
PaneItemEntry(
|
PaneItemEntry({
|
||||||
{required this.label, required this.icon, required this.activeIcon});
|
required this.label,
|
||||||
|
required this.icon,
|
||||||
|
required this.activeIcon,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class PaneActionEntry {
|
class PaneActionEntry {
|
||||||
@@ -18,20 +21,24 @@ class PaneActionEntry {
|
|||||||
|
|
||||||
VoidCallback onTap;
|
VoidCallback onTap;
|
||||||
|
|
||||||
PaneActionEntry(
|
PaneActionEntry({
|
||||||
{required this.label, required this.icon, required this.onTap});
|
required this.label,
|
||||||
|
required this.icon,
|
||||||
|
required this.onTap,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class NaviPane extends StatefulWidget {
|
class NaviPane extends StatefulWidget {
|
||||||
const NaviPane(
|
const NaviPane({
|
||||||
{required this.paneItems,
|
required this.paneItems,
|
||||||
required this.paneActions,
|
required this.paneActions,
|
||||||
required this.pageBuilder,
|
required this.pageBuilder,
|
||||||
this.initialPage = 0,
|
this.initialPage = 0,
|
||||||
this.onPageChanged,
|
this.onPageChanged,
|
||||||
required this.observer,
|
required this.observer,
|
||||||
required this.navigatorKey,
|
required this.navigatorKey,
|
||||||
super.key});
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
final List<PaneItemEntry> paneItems;
|
final List<PaneItemEntry> paneItems;
|
||||||
|
|
||||||
@@ -187,7 +194,8 @@ class NaviPaneState extends State<NaviPane>
|
|||||||
child: buildLeft(),
|
child: buildLeft(),
|
||||||
),
|
),
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
left: _kFoldedSideBarWidth * ((value - 1).clamp(0, 1)) +
|
left:
|
||||||
|
_kFoldedSideBarWidth * ((value - 1).clamp(0, 1)) +
|
||||||
(_kSideBarWidth - _kFoldedSideBarWidth) *
|
(_kSideBarWidth - _kFoldedSideBarWidth) *
|
||||||
((value - 2).clamp(0, 1)),
|
((value - 2).clamp(0, 1)),
|
||||||
child: buildMainView(),
|
child: buildMainView(),
|
||||||
@@ -202,6 +210,10 @@ class NaviPaneState extends State<NaviPane>
|
|||||||
Widget buildMainView() {
|
Widget buildMainView() {
|
||||||
return HeroControllerScope(
|
return HeroControllerScope(
|
||||||
controller: MaterialApp.createMaterialHeroController(),
|
controller: MaterialApp.createMaterialHeroController(),
|
||||||
|
child: NavigatorPopHandler(
|
||||||
|
onPopWithResult: (result) {
|
||||||
|
widget.navigatorKey.currentState?.maybePop(result);
|
||||||
|
},
|
||||||
child: Navigator(
|
child: Navigator(
|
||||||
observers: [widget.observer],
|
observers: [widget.observer],
|
||||||
key: widget.navigatorKey,
|
key: widget.navigatorKey,
|
||||||
@@ -212,6 +224,7 @@ class NaviPaneState extends State<NaviPane>
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,7 +252,7 @@ class NaviPaneState extends State<NaviPane>
|
|||||||
icon: Icon(action.icon),
|
icon: Icon(action.icon),
|
||||||
onPressed: action.onTap,
|
onPressed: action.onTap,
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -261,9 +274,7 @@ class NaviPaneState extends State<NaviPane>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: List<Widget>.generate(
|
children: List<Widget>.generate(widget.paneItems.length, (index) {
|
||||||
widget.paneItems.length,
|
|
||||||
(index) {
|
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: _SingleBottomNaviWidget(
|
child: _SingleBottomNaviWidget(
|
||||||
enabled: currentPage == index,
|
enabled: currentPage == index,
|
||||||
@@ -274,8 +285,7 @@ class NaviPaneState extends State<NaviPane>
|
|||||||
key: ValueKey(index),
|
key: ValueKey(index),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -286,7 +296,8 @@ class NaviPaneState extends State<NaviPane>
|
|||||||
const paddingHorizontal = 12.0;
|
const paddingHorizontal = 12.0;
|
||||||
return Material(
|
return Material(
|
||||||
child: Container(
|
child: Container(
|
||||||
width: _kFoldedSideBarWidth +
|
width:
|
||||||
|
_kFoldedSideBarWidth +
|
||||||
(_kSideBarWidth - _kFoldedSideBarWidth) * ((value - 2).clamp(0, 1)),
|
(_kSideBarWidth - _kFoldedSideBarWidth) * ((value - 2).clamp(0, 1)),
|
||||||
height: double.infinity,
|
height: double.infinity,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: paddingHorizontal),
|
padding: const EdgeInsets.symmetric(horizontal: paddingHorizontal),
|
||||||
@@ -323,9 +334,7 @@ class NaviPaneState extends State<NaviPane>
|
|||||||
key: ValueKey(index + widget.paneItems.length),
|
key: ValueKey(index + widget.paneItems.length),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(height: 16),
|
||||||
height: 16,
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -334,12 +343,13 @@ class NaviPaneState extends State<NaviPane>
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _SideNaviWidget extends StatelessWidget {
|
class _SideNaviWidget extends StatelessWidget {
|
||||||
const _SideNaviWidget(
|
const _SideNaviWidget({
|
||||||
{required this.enabled,
|
required this.enabled,
|
||||||
required this.entry,
|
required this.entry,
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
required this.showTitle,
|
required this.showTitle,
|
||||||
super.key});
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
final bool enabled;
|
final bool enabled;
|
||||||
|
|
||||||
@@ -368,18 +378,18 @@ class _SideNaviWidget extends StatelessWidget {
|
|||||||
? Row(
|
? Row(
|
||||||
children: [icon, const SizedBox(width: 12), Text(entry.label)],
|
children: [icon, const SizedBox(width: 12), Text(entry.label)],
|
||||||
)
|
)
|
||||||
: Align(
|
: Align(alignment: Alignment.centerLeft, child: icon),
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: icon,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
).paddingVertical(4);
|
).paddingVertical(4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PaneActionWidget extends StatelessWidget {
|
class _PaneActionWidget extends StatelessWidget {
|
||||||
const _PaneActionWidget(
|
const _PaneActionWidget({
|
||||||
{required this.entry, required this.showTitle, super.key});
|
required this.entry,
|
||||||
|
required this.showTitle,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
final PaneActionEntry entry;
|
final PaneActionEntry entry;
|
||||||
|
|
||||||
@@ -399,21 +409,19 @@ class _PaneActionWidget extends StatelessWidget {
|
|||||||
? Row(
|
? Row(
|
||||||
children: [icon, const SizedBox(width: 12), Text(entry.label)],
|
children: [icon, const SizedBox(width: 12), Text(entry.label)],
|
||||||
)
|
)
|
||||||
: Align(
|
: Align(alignment: Alignment.centerLeft, child: icon),
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: icon,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
).paddingVertical(4);
|
).paddingVertical(4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SingleBottomNaviWidget extends StatefulWidget {
|
class _SingleBottomNaviWidget extends StatefulWidget {
|
||||||
const _SingleBottomNaviWidget(
|
const _SingleBottomNaviWidget({
|
||||||
{required this.enabled,
|
required this.enabled,
|
||||||
required this.entry,
|
required this.entry,
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
super.key});
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
final bool enabled;
|
final bool enabled;
|
||||||
|
|
||||||
@@ -482,8 +490,9 @@ class _SingleBottomNaviWidgetState extends State<_SingleBottomNaviWidget>
|
|||||||
Widget buildContent() {
|
Widget buildContent() {
|
||||||
final value = controller.value;
|
final value = controller.value;
|
||||||
final colorScheme = Theme.of(context).colorScheme;
|
final colorScheme = Theme.of(context).colorScheme;
|
||||||
final icon =
|
final icon = Icon(
|
||||||
Icon(widget.enabled ? widget.entry.activeIcon : widget.entry.icon);
|
widget.enabled ? widget.entry.activeIcon : widget.entry.icon,
|
||||||
|
);
|
||||||
return Center(
|
return Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 64,
|
width: 64,
|
||||||
@@ -570,8 +579,11 @@ class NaviObserver extends NavigatorObserver implements Listenable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _NaviPopScope extends StatelessWidget {
|
class _NaviPopScope extends StatelessWidget {
|
||||||
const _NaviPopScope(
|
const _NaviPopScope({
|
||||||
{required this.child, this.popGesture = false, required this.action});
|
required this.child,
|
||||||
|
this.popGesture = false,
|
||||||
|
required this.action,
|
||||||
|
});
|
||||||
|
|
||||||
final Widget child;
|
final Widget child;
|
||||||
final bool popGesture;
|
final bool popGesture;
|
||||||
@@ -581,15 +593,7 @@ class _NaviPopScope extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget res = App.isIOS
|
Widget res = child;
|
||||||
? child
|
|
||||||
: PopScope(
|
|
||||||
canPop: App.isAndroid ? false : true,
|
|
||||||
onPopInvokedWithResult: (value, result) {
|
|
||||||
action();
|
|
||||||
},
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
if (popGesture) {
|
if (popGesture) {
|
||||||
res = GestureDetector(
|
res = GestureDetector(
|
||||||
onPanStart: (details) {
|
onPanStart: (details) {
|
||||||
@@ -606,7 +610,8 @@ class _NaviPopScope extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
panStartAtEdge = false;
|
panStartAtEdge = false;
|
||||||
},
|
},
|
||||||
child: res);
|
child: res,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@ import 'dart:math';
|
|||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:venera/foundation/app.dart';
|
||||||
|
|
||||||
const double _kBackGestureWidth = 20.0;
|
const double _kBackGestureWidth = 20.0;
|
||||||
const int _kMaxDroppedSwipePageForwardAnimationTime = 800;
|
const int _kMaxDroppedSwipePageForwardAnimationTime = 800;
|
||||||
@@ -115,7 +116,14 @@ mixin _AppRouteTransitionMixin<T> on PageRoute<T> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
|
Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
|
||||||
return SlidePageTransitionBuilder().buildTransitions(
|
PageTransitionsBuilder builder;
|
||||||
|
if (App.isAndroid) {
|
||||||
|
builder = PredictiveBackPageTransitionsBuilder();
|
||||||
|
} else {
|
||||||
|
builder = SlidePageTransitionBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.buildTransitions(
|
||||||
this,
|
this,
|
||||||
context,
|
context,
|
||||||
animation,
|
animation,
|
||||||
|
Reference in New Issue
Block a user