shell_route_transitions 0.0.2
shell_route_transitions: ^0.0.2 copied to clipboard
A Flutter package that provides beautiful and customizable transitions for shell routes in Flutter applications.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:flutter_web_plugins/url_strategy.dart';
import 'package:shell_route_transitions/animated_stateful_shell_route.dart';
import 'package:shell_route_transitions/route_transition.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
usePathUrlStrategy();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp.router(
title: 'Shell Route Transitions Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
routerConfig: goRouter,
);
}
}
class ScaffoldWithNestedNavigation extends StatelessWidget {
const ScaffoldWithNestedNavigation({Key? key, required this.navigationShell})
: super(key: key ?? const ValueKey<String>('ScaffoldWithNestedNavigation'));
final StatefulNavigationShell navigationShell;
void _goBranch(int index) {
navigationShell.goBranch(
index,
initialLocation: index == navigationShell.currentIndex,
);
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 450) {
return ScaffoldWithNavigationBar(
body: navigationShell,
selectedIndex: navigationShell.currentIndex,
onDestinationSelected: _goBranch,
);
} else {
return ScaffoldWithNavigationRail(
body: navigationShell,
selectedIndex: navigationShell.currentIndex,
onDestinationSelected: _goBranch,
);
}
},
);
}
}
class ScaffoldWithNavigationBar extends StatelessWidget {
const ScaffoldWithNavigationBar({
super.key,
required this.body,
required this.selectedIndex,
required this.onDestinationSelected,
});
final Widget body;
final int selectedIndex;
final ValueChanged<int> onDestinationSelected;
@override
Widget build(BuildContext context) {
return Scaffold(
body: body,
bottomNavigationBar: NavigationBar(
selectedIndex: selectedIndex,
destinations: const [
NavigationDestination(label: 'Section A', icon: Icon(Icons.home)),
NavigationDestination(label: 'Section B', icon: Icon(Icons.settings)),
NavigationDestination(label: 'Section C', icon: Icon(Icons.person)),
],
onDestinationSelected: onDestinationSelected,
),
);
}
}
class ScaffoldWithNavigationRail extends StatelessWidget {
const ScaffoldWithNavigationRail({
super.key,
required this.body,
required this.selectedIndex,
required this.onDestinationSelected,
});
final Widget body;
final int selectedIndex;
final ValueChanged<int> onDestinationSelected;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: [
NavigationRail(
selectedIndex: selectedIndex,
onDestinationSelected: onDestinationSelected,
labelType: NavigationRailLabelType.all,
destinations: const <NavigationRailDestination>[
NavigationRailDestination(
label: Text('Section A'),
icon: Icon(Icons.home),
),
NavigationRailDestination(
label: Text('Section B'),
icon: Icon(Icons.settings),
),
],
),
const VerticalDivider(thickness: 1, width: 1),
Expanded(child: body),
],
),
);
}
}
class RootScreen extends StatelessWidget {
const RootScreen({required this.label, required this.detailsPath, super.key});
final String label;
final String detailsPath;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Tab root - $label')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Screen $label',
style: Theme.of(context).textTheme.titleLarge,
),
const Padding(padding: EdgeInsets.all(4)),
TextButton(
onPressed: () => context.go(detailsPath),
child: const Text('View details'),
),
],
),
),
);
}
}
final goRouter = GoRouter(
initialLocation: '/a',
debugLogDiagnostics: true,
routes: [
AnimatedStatefulShellRoute(
transitionDuration: const Duration(milliseconds: 300),
transitionBuilder: ShellRouteTransitions.scale,
builder: (context, state, navigationShell) {
return ScaffoldWithNestedNavigation(navigationShell: navigationShell);
},
branches: [
StatefulShellBranch(
routes: [
GoRoute(
path: '/a',
builder:
(context, state) =>
const RootScreen(label: 'A', detailsPath: '/a/details'),
),
],
),
StatefulShellBranch(
routes: [
GoRoute(
path: '/b',
builder:
(context, state) =>
const RootScreen(label: 'B', detailsPath: '/b/details'),
),
],
),
StatefulShellBranch(
routes: [
GoRoute(
path: '/c',
builder:
(context, state) =>
const RootScreen(label: 'C', detailsPath: '/c/details'),
),
],
),
],
),
],
);