gpt4 book ai didi

Flutter导航推送,同时保持相同的Appbar

转载 作者:行者123 更新时间:2023-12-05 03:43:31 29 4
gpt4 key购买 nike

我目前正在构建一个 Flutter 应用程序,我正在努力找出实现导航的最佳方式。

我有 2 个页面,它们是:

  • 主页:我想从那里使用 IndexedStack 来管理提要。
  • ProfilePage:个人资料页面,它(在图形上)与主页共享相同的 AppBar 和相同的 Drawer。

在我的应用程序中,用户在登录后立即到达主页。不涉及导航。

从那里,我现在有一个 TextButton,它调用 Navigator.of(context).pushNamed(AppRoutes.profile)

正如我所说,两个页面共享同一个 Appbar 和 Drawer,所以我创建了一个自定义的 myScaffold。两个页面都使用这个脚手架。

因此行为是正确的,因为在单击按钮后,ProfilePage 会移到 HomePage 上。

我的问题是应用栏在图形上应该保持不变,但是当推送个人资料页面时,动画清楚地表明它不是同一个应用栏。

  • 是否可以动画化个人资料页面的条目,而无需动画化应用栏的重建?

  • 或者是否可以将路由直接推送到脚手架内容中?

  • 作为替代方案,我只是想编写一个函数,它返回要在脚手架内容中显示的页面小部件。但是这种方法对我来说似乎不对,因为有路线。

从官方文档中Interactive example可以看出我的意思: Docs

当第二条路线建立在第一条路线之上时,一个新的 Appbar 将建立在前一条路线之上。但是,如果我需要应用栏保持不变怎么办?

最佳答案

您可以使用 Navigator 创建子导航器类。

我在当前项目中创建了一个路由库 (routes.dart),用于在 bottomNavigationBar 仍显示时导航到其他屏幕。使用相同的想法,您可以在使用相同的 AppBar 时执行导航。

这是您的场景的示例代码。

ma​​in.dart

import 'package:flutter/material.dart';
import 'package:flutter2sample/routes.dart';

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
navigatorKey: Routes.rootNavigatorKey,
initialRoute: Routes.PAGE_INITIAL,
onGenerateRoute: Routes.onGenerateRoute,
);
}
}

routes.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter2sample/pages/home_page.dart';
import 'package:flutter2sample/pages/initial_page.dart';
import 'package:flutter2sample/pages/main_page.dart';
import 'package:flutter2sample/pages/profile_page.dart';

class Routes {
Routes._();

static const String PAGE_INITIAL = '/';
static const String PAGE_MAIN = '/main';
static const String PAGE_HOME = '/home';
static const String PAGE_PROFILE = '/profile';

static final GlobalKey<NavigatorState> rootNavigatorKey =
GlobalKey<NavigatorState>();
static final GlobalKey<NavigatorState> mainNavigatorKey =
GlobalKey<NavigatorState>();

static String currentSubNavigatorInitialRoute;

static CupertinoPageRoute<Widget> onGenerateRoute(RouteSettings settings) {
Widget page;

switch (settings.name) {
case PAGE_INITIAL:
page = InitialPage();
break;
case PAGE_MAIN:
page = MainPage();
break;
case PAGE_HOME:
page = HomePage();
break;
case PAGE_PROFILE:
page = ProfilePage();
break;
}

if (settings.name == PAGE_INITIAL &&
currentSubNavigatorInitialRoute != null) {
// When current sub-navigator initial route is set,
// do not display initial route because it is already displayed.
return null;
}

return CupertinoPageRoute<Widget>(
builder: (_) {
if (currentSubNavigatorInitialRoute == settings.name) {
return WillPopScope(
onWillPop: () async => false,
child: page,
);
}

return page;
},
settings: settings,
);
}

/// [MaterialApp] navigator key.
///
///
static NavigatorState get rootNavigator => rootNavigatorKey.currentState;

/// [PAGE_MAIN] navigator key.
///
///
static NavigatorState get mainNavigator => mainNavigatorKey.currentState;

/// Navigate to screen via [CupertinoPageRoute].
///
/// If [navigator] is not set, it will use the [rootNavigator].
static void push(Widget screen, {NavigatorState navigator}) {
final CupertinoPageRoute<Widget> route = CupertinoPageRoute<Widget>(
builder: (_) => screen,
);

if (navigator != null) {
navigator.push(route);
return;
}

rootNavigator.push(route);
}

/// Navigate to route name via [CupertinoPageRoute].
///
/// If [navigator] is not set, it will use the [rootNavigator].
static void pushNamed(
String routeName, {
NavigatorState navigator,
Object arguments,
}) {
if (navigator != null) {
navigator.pushNamed(routeName, arguments: arguments);
return;
}

rootNavigator.pushNamed(routeName, arguments: arguments);
}

/// Pop current route of [navigator].
///
/// If [navigator] is not set, it will use the [rootNavigator].
static void pop<T extends Object>({
NavigatorState navigator,
T result,
}) {
if (navigator != null) {
navigator.pop(result);
return;
}

rootNavigator.pop(result);
}
}

//--------------------------------------------------------------------------------
/// A navigator widget who is a child of [MaterialApp] navigator.
///
///
class SubNavigator extends StatelessWidget {
const SubNavigator({
@required this.navigatorKey,
@required this.initialRoute,
Key key,
}) : super(key: key);

final GlobalKey<NavigatorState> navigatorKey;
final String initialRoute;

@override
Widget build(BuildContext context) {
final _SubNavigatorObserver _navigatorObserver = _SubNavigatorObserver(
initialRoute,
navigatorKey,
);
Routes.currentSubNavigatorInitialRoute = initialRoute;

return WillPopScope(
onWillPop: () async {
if (_navigatorObserver.isInitialPage) {
Routes.currentSubNavigatorInitialRoute = null;
await SystemNavigator.pop();
return true;
}

final bool canPop = navigatorKey.currentState.canPop();

if (canPop) {
navigatorKey.currentState.pop();
}

return !canPop;
},
child: Navigator(
key: navigatorKey,
observers: <NavigatorObserver>[_navigatorObserver],
initialRoute: initialRoute,
onGenerateRoute: Routes.onGenerateRoute,
),
);
}
}

//--------------------------------------------------------------------------------
/// [NavigatorObserver] of [SubNavigator] widget.
///
///
class _SubNavigatorObserver extends NavigatorObserver {
_SubNavigatorObserver(this._initialRoute, this._navigatorKey);

final String _initialRoute;
final GlobalKey<NavigatorState> _navigatorKey;
final List<String> _routeNameStack = <String>[];

bool _isInitialPage = false;

/// Flag if current route is the initial page.
///
///
bool get isInitialPage => _isInitialPage;

@override
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
_routeNameStack.add(route.settings.name);
_isInitialPage = _routeNameStack.last == _initialRoute;
}

@override
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
_routeNameStack.remove(route.settings.name);
_isInitialPage = _routeNameStack.last == _initialRoute;
}

@override
void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) {
_routeNameStack.remove(route.settings.name);
_isInitialPage = _routeNameStack.last == _initialRoute;
}

@override
void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) {
_routeNameStack.remove(oldRoute.settings.name);
_routeNameStack.add(newRoute.settings.name);
_isInitialPage = _routeNameStack.last == _initialRoute;
}
}

initial_page.dart

import 'package:flutter/material.dart';
import 'package:flutter2sample/routes.dart';

class InitialPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Initial Page'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('This is INITIAL page'),
TextButton(
onPressed: () => Routes.pushNamed(Routes.PAGE_MAIN),
child: const Text('To Main page'),
),
],
),
),
);
}
}

ma​​in_page.dart

import 'package:flutter/material.dart';
import 'package:flutter2sample/routes.dart';

class MainPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Main Page'),
),
body: SubNavigator(
navigatorKey: Routes.mainNavigatorKey,
initialRoute: Routes.PAGE_HOME,
),
);
}
}

home_page.dart

import 'package:flutter/material.dart';
import 'package:flutter2sample/routes.dart';

class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.yellow,
body: SafeArea(
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('This is HOME page'),
TextButton(
onPressed: () => Routes.pushNamed(
Routes.PAGE_PROFILE,
navigator: Routes.mainNavigator,
),
child: const Text('To Profile page'),
),
],
),
),
),
);
}
}

profile_page.dart

import 'package:flutter/material.dart';
import 'package:flutter2sample/routes.dart';

class ProfilePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
body: SafeArea(
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('This is PROFILE page'),
TextButton(
onPressed: () => Routes.pop(navigator: Routes.mainNavigator),
child: const Text('Back to Home page'),
),
],
),
),
),
);
}
}

关于Flutter导航推送,同时保持相同的Appbar,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66755344/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com