Skip to content

Instantly share code, notes, and snippets.

@SuperPenguin
Created September 5, 2024 03:14
Show Gist options
  • Save SuperPenguin/2ed3ec1c897574bd20c8408cfabb5684 to your computer and use it in GitHub Desktop.
Save SuperPenguin/2ed3ec1c897574bd20c8408cfabb5684 to your computer and use it in GitHub Desktop.
GoRouter Tab example
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
void main() {
runApp(const App());
}
class App extends StatefulWidget {
const App({super.key});
@override
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
late final GoRouter _goRouter;
@override
void initState() {
super.initState();
_goRouter = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => const HomeScreen(),
routes: [
GoRoute(
path: 'tabExample/:tab',
builder: (context, state) {
final String tab = state.pathParameters['tab'] ?? 'a';
return TabExampleScreen(
tab: tab,
);
},
routes: [
GoRoute(
path: 'subpage',
builder: (context, state) => const SubpageScreen(),
),
],
),
],
),
],
);
}
@override
void dispose() {
_goRouter.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp.router(
debugShowCheckedModeBanner: false,
routerConfig: _goRouter,
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Demo'),
),
body: ListView(
children: [
ListTile(
title: const Text('Tab Example'),
onTap: () {
GoRouter.of(context).go('/tabExample/a');
},
),
],
),
);
}
}
class TabExampleScreen extends StatefulWidget {
const TabExampleScreen({
super.key,
required this.tab,
});
final String tab;
@override
State<TabExampleScreen> createState() => _TabExampleScreenState();
}
class _TabExampleScreenState extends State<TabExampleScreen>
with SingleTickerProviderStateMixin {
late final TabController _tabController;
void _tabListener() {
if (!_tabController.indexIsChanging) {
const Map<int, String> indexToTab = {
0: 'a',
1: 'b',
2: 'c',
};
final String tab = indexToTab[_tabController.index] ?? 'a';
final current = GoRouter.of(context).routeInformationProvider.value.uri;
final paths = current.pathSegments.toList();
if (paths.length < 2) {
return;
}
paths[1] = tab;
paths.insert(0, ''); // insert empty so it would start with /
final target = current.replace(pathSegments: paths);
GoRouter.of(context).go(target.toString());
}
}
void _goToSubpage() {
final current = GoRouter.of(context).routeInformationProvider.value.uri;
final paths = current.pathSegments.toList();
if (paths.length < 2) {
return;
}
final tab = paths[1];
GoRouter.of(context).go('/tabExample/$tab/subpage');
}
@override
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
_tabController.addListener(_tabListener);
}
@override
void didUpdateWidget(covariant TabExampleScreen oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.tab != widget.tab) {
const Map<String, int> tabToIndex = {
'a': 0,
'b': 1,
'c': 2,
};
final int targetIndex = tabToIndex[widget.tab] ?? 0;
if (_tabController.index != targetIndex) {
_tabController.animateTo(targetIndex);
}
}
}
@override
void dispose() {
_tabController.removeListener(_tabListener);
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Tab Example'),
bottom: TabBar(
controller: _tabController,
tabs: const [
Tab(child: Text('A')),
Tab(child: Text('B')),
Tab(child: Text('C')),
],
),
),
body: TabBarView(
controller: _tabController,
children: [
Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text('A'),
FilledButton(
onPressed: _goToSubpage,
child: const Text('Go To Subpage'),
),
],
),
),
Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text('B'),
FilledButton(
onPressed: _goToSubpage,
child: const Text('Go To Subpage'),
),
],
),
),
Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text('C'),
FilledButton(
onPressed: _goToSubpage,
child: const Text('Go To Subpage'),
),
],
),
),
],
),
);
}
}
class SubpageScreen extends StatelessWidget {
const SubpageScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Subpage'),
),
body: Center(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
FilledButton(
onPressed: () {
GoRouter.of(context).go('/tabExample/a/subpage');
},
child: const Text('A'),
),
FilledButton(
onPressed: () {
GoRouter.of(context).go('/tabExample/b/subpage');
},
child: const Text('B'),
),
FilledButton(
onPressed: () {
GoRouter.of(context).go('/tabExample/c/subpage');
},
child: const Text('C'),
),
],
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment