Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/go_router/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 14.2.8

- Updated custom_stateful_shell_route example to better support swiping in TabView as well as demonstration of the use of PageView.

## 14.2.7

- Fixes issue so that the parseRouteInformationWithContext can handle non-http Uris.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';

import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
Expand Down Expand Up @@ -78,13 +80,13 @@ class NestedTabNavigationExampleApp extends StatelessWidget {
],
),

// The route branch for the third tab of the bottom navigation bar.
// The route branch for the second tab of the bottom navigation bar.
StatefulShellBranch(
// StatefulShellBranch will automatically use the first descendant
// GoRoute as the initial location of the branch. If another route
// is desired, specify the location of it using the defaultLocation
// parameter.
// defaultLocation: '/c2',
// defaultLocation: '/b2',
routes: <RouteBase>[
StatefulShellRoute(
builder: (BuildContext context, GoRouterState state,
Expand Down Expand Up @@ -271,7 +273,7 @@ class RootScreenA extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Root of section A'),
title: const Text('Section A root'),
),
body: Center(
child: Column(
Expand Down Expand Up @@ -387,6 +389,10 @@ class TabbedRootScreen extends StatefulWidget {

@override
State<StatefulWidget> createState() => _TabbedRootScreenState();

/// To use an alternative implementation using a PageView, replace the line
/// above with the one below:
//State<StatefulWidget> createState() => _TabbedRootScreenStatePageView();
}

class _TabbedRootScreenState extends State<TabbedRootScreen>
Expand All @@ -396,6 +402,25 @@ class _TabbedRootScreenState extends State<TabbedRootScreen>
vsync: this,
initialIndex: widget.navigationShell.currentIndex);

void _switchedTab() {
if (_tabController.index != widget.navigationShell.currentIndex) {
widget.navigationShell.goBranch(_tabController.index);
}
}

@override
void initState() {
super.initState();
_tabController.addListener(_switchedTab);
}

@override
void dispose() {
_tabController.removeListener(_switchedTab);
_tabController.dispose();
super.dispose();
}

@override
void didUpdateWidget(covariant TabbedRootScreen oldWidget) {
super.didUpdateWidget(oldWidget);
Expand All @@ -410,7 +435,8 @@ class _TabbedRootScreenState extends State<TabbedRootScreen>

return Scaffold(
appBar: AppBar(
title: const Text('Root of Section B (nested TabBar shell)'),
title: Text(
'Section B root (tab: ${widget.navigationShell.currentIndex + 1})'),
bottom: TabBar(
controller: _tabController,
tabs: tabs,
Expand All @@ -428,6 +454,90 @@ class _TabbedRootScreenState extends State<TabbedRootScreen>
}
}

/// Alternative implementation _TabbedRootScreenState, demonstrating the use of
/// a PageView.
// ignore: unused_element
class _TabbedRootScreenStatePageView extends State<TabbedRootScreen>
with SingleTickerProviderStateMixin {
late final PageController _pageController = PageController(
initialPage: widget.navigationShell.currentIndex,
);
Timer? _throttle;

void _scrolledPageView() {
// Simple throttling implementation to handle scroll events.
int nextPage() => (_pageController.page ?? 0).round();
if (nextPage() != widget.navigationShell.currentIndex) {
_throttle?.cancel();
_throttle = Timer(const Duration(milliseconds: 100), () {
widget.navigationShell.goBranch(nextPage());
_throttle = null;
});
}
}

@override
void initState() {
super.initState();
_pageController.addListener(_scrolledPageView);
}

@override
void dispose() {
_pageController.removeListener(_scrolledPageView);
_pageController.dispose();
super.dispose();
}

@override
void didUpdateWidget(covariant TabbedRootScreen oldWidget) {
super.didUpdateWidget(oldWidget);
_pageController.jumpToPage(widget.navigationShell.currentIndex);
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Section B root (tab ${widget.navigationShell.currentIndex + 1})'),
),
body: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
ElevatedButton(
onPressed: () => _onTabTap(0),
child: const Text('Tab 1'),
),
ElevatedButton(
onPressed: () => _onTabTap(1),
child: const Text('Tab 2'),
),
]),
Expanded(
child: PageView(
controller: _pageController,
children: widget.children,
),
),
],
),
);
}

void _onTabTap(int index) {
if (_pageController.hasClients) {
_pageController.animateToPage(
index,
duration: const Duration(milliseconds: 500),
curve: Curves.bounceOut,
);
}
}
}

/// Widget for the pages in the top tab bar.
class TabScreen extends StatelessWidget {
/// Creates a RootScreen
Expand Down
2 changes: 1 addition & 1 deletion packages/go_router/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: go_router
description: A declarative router for Flutter based on Navigation 2 supporting
deep linking, data-driven routes and more
version: 14.2.7
version: 14.2.8
repository: https://github.com/flutter/packages/tree/main/packages/go_router
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router%22

Expand Down