flutter/examples/api/lib/widgets/page/page_can_pop.0.dart
chunhtai a36ff80cf6
Refactors page API (#137792)
fixes https://github.com/flutter/flutter/issues/137458

Chagnes:
1. Navigator.pop will always pop page based route
2. add a onDidRemovePage callback to replace onPopPage
3. Page.canPop and Page.onPopInvoked mirrors the PopScope, but in Page class.

migration guide https://github.com/flutter/website/pull/10523
2024-05-13 22:45:51 +00:00

161 lines
4.1 KiB
Dart

// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This sample demonstrates showing a confirmation dialog before navigating
// away from a page.
import 'package:flutter/material.dart';
void main() => runApp(const PageApiExampleApp());
class PageApiExampleApp extends StatefulWidget {
const PageApiExampleApp({super.key});
@override
State<PageApiExampleApp> createState() => _PageApiExampleAppState();
}
class _PageApiExampleAppState extends State<PageApiExampleApp> {
final RouterDelegate<Object> delegate = MyRouterDelegate();
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerDelegate: delegate,
);
}
}
class MyRouterDelegate extends RouterDelegate<Object> with PopNavigatorRouterDelegateMixin<Object>, ChangeNotifier {
// This example doesn't use RouteInformationProvider.
@override
Future<void> setNewRoutePath(Object configuration) async => throw UnimplementedError();
@override
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
static MyRouterDelegate of(BuildContext context) => Router.of(context).routerDelegate as MyRouterDelegate;
bool get showDetailPage => _showDetailPage;
bool _showDetailPage = false;
set showDetailPage(bool value) {
if (_showDetailPage == value) {
return;
}
_showDetailPage = value;
notifyListeners();
}
Future<bool> _showConfirmDialog() async {
return await showDialog<bool>(
context: navigatorKey.currentContext!,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Are you sure?'),
actions: <Widget>[
TextButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop(false);
},
),
TextButton(
child: const Text('Confirm'),
onPressed: () {
Navigator.of(context).pop(true);
},
),
],
);
},
) ?? false;
}
Future<void> _handlePopDetails(bool didPop, void result) async {
if (didPop) {
showDetailPage = false;
return;
}
final bool confirmed = await _showConfirmDialog();
if (confirmed) {
showDetailPage = false;
}
}
List<Page<Object?>> _getPages() {
return <Page<Object?>>[
const MaterialPage<void>(key: ValueKey<String>('home'), child: _HomePage()),
if (showDetailPage)
MaterialPage<void>(
key: const ValueKey<String>('details'),
child: const _DetailsPage(),
canPop: false,
onPopInvoked: _handlePopDetails,
),
];
}
@override
Widget build(BuildContext context) {
return Navigator(
key: navigatorKey,
pages: _getPages(),
onDidRemovePage: (Page<Object?> page) {
assert(page.key == const ValueKey<String>('details'));
showDetailPage = false;
},
);
}
}
class _HomePage extends StatefulWidget {
const _HomePage();
@override
State<_HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<_HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home')),
body: Center(
child: TextButton(
onPressed: () {
MyRouterDelegate.of(context).showDetailPage = true;
},
child: const Text('Go to details'),
),
),
);
}
}
class _DetailsPage extends StatefulWidget {
const _DetailsPage();
@override
State<_DetailsPage> createState() => _DetailsPageState();
}
class _DetailsPageState extends State<_DetailsPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Details')),
body: Center(
child: TextButton(
onPressed: () {
Navigator.of(context).maybePop();
},
child: const Text('Go back'),
),
),
);
}
}