Flutter中的导航介绍
移动应用程序最基本的方面之一是用户能够在不同页面之间移动。 对我们来说幸运的是,Flutter 让创建路线和在屏幕之间移动变得非常容易,尤其是与许多前端解决方案相比。
项目文件设置
对于我们的示例,我们将有 4 个屏幕,我们的 main.dart 文件,并将导航栏分成自己的文件。
* screens 📂 * account_screen.dart * balance_screen.dart * transfer_screen.dart * welcome_screen.dart * main.dart * navbar.dart
命名路由
虽然在大多数情况下您希望将每条路由分解为自己的文件,但我们现在将它们放在我们的 main.dart 中。
在我们的 MaterialApp 中,我们可以设置 routes 映射,它是键/值对的列表。 此地图中的每个项目都将一个字符串值链接到一个回调函数,该函数返回我们要呈现的页面。 这样做的目的是通过让我们在需要新页面时折腾类似 'welcome_screen' 之类的东西来加快开发速度,而不是完整的 (context) => WelcomeScreen()。
要设置我们的主页,我们可以使用 MaterialApp 的 home 属性或 initialRoute 属性。 他们有效地做同样的事情,但 home 获取类本身,如 WelcomeScreen(),而 initialRoute 从我们的 routes 映射中获取密钥。 您不能同时使用两者,因为这会使编译器感到困惑。
主要.dart
import 'package:flutter/material.dart';
import './screens/welcome_screen.dart';
import './screens/account_screen.dart';
import './screens/balance_screen.dart';
import './screens/transfer_screen.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Navigation Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: WelcomeScreen(),
routes: {
'welcome_screen': (context) => WelcomeScreen(),
'account_screen': (context) => AccountScreen(),
'balance_screen': (context) => BalanceScreen(),
'transfer_screen': (context) => TransferScreen()
});
}
}
这很好用,但是您最终可能会经常键入这些路由中的每一个,并且当您打出最轻微的错字时,仅使用字符串就会使调试变得困难。 相反,将每个键存储在每个类中的静态 id 变量中并仅访问该 id 会使我们的代码不那么脆弱。 这也将使我们受益于 VSCode 的 IntelliSense,并帮助找出页面可能不可用的原因。
我们示例中的每个屏幕都是相同的,除了 id 和文本小部件。 我们还将底部导航栏设置为稍后将创建的小部件。
Welcome_screen.dart
import 'package:flutter/material.dart';
import '../navbar.dart';
class WelcomeScreen extends StatelessWidget {
static const String id = 'welcome_screen';
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
bottomNavigationBar: Navbar(),
child: Text('Welcome'),
),
);
}
}
现在我们可以用每个屏幕的 id 替换我们的字符串。 请注意,我们在没有实际调用类本身的情况下访问它。
主要.dart
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return MaterialApp(initialRoute: WelcomeScreen.id, routes: {
WelcomeScreen.id: (context) => WelcomeScreen(),
AccountScreen.id: (context) => AccountScreen(),
BalanceScreen.id: (context) => BalanceScreen(),
TransferScreen.id: (context) => TransferScreen()
});
}
}
推送和弹出
与前端 Web 开发不同,移动路由基于“堆叠”屏幕。 当我们从欢迎屏幕导航到帐户屏幕时,我们并没有真正更改页面,而是将我们的帐户屏幕添加到我们的堆栈中,从而覆盖了前一页。 要返回欢迎屏幕,我们只需要销毁或关闭 pop 最上层,显示其下方已呈现的页面。
Navigator 上有很多不同的方法可以做到这一点,您可以在 此处 充分探索。 我们需要的主要两个是 pushNamed 添加到我们的堆栈和 pop 删除最新的层。 pop 只需要我们构建的 context 和 push 方法需要 context 和我们在路由中设置的页面键。
任何带有 Named 的方法都适用于当我们在 MaterialApp 中设置路由时,否则您可以传入回调本身而不是我们的键。
导航栏.dart
import 'package:flutter/material.dart';
import './screens/account_screen.dart';
import './screens/balance_screen.dart';
import './screens/transfer_screen.dart';
class Navbar extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
FlatButton(
onPressed: () => Navigator.pop(context),
child: Icon(Icons.arrow_left, color: Colors.white, size: 40)),
FlatButton(
onPressed: () => Navigator.pushNamed(context, BalanceScreen.id),
child: Icon(Icons.account_balance, color: Colors.white)),
FlatButton(
onPressed: () => Navigator.pushNamed(context, TransferScreen.id),
child: Icon(Icons.sync, color: Colors.white)),
FlatButton(
onPressed: () => Navigator.pushNamed(context, AccountScreen.id),
child: Icon(Icons.account_circle, color: Colors.white)),
],
),
);
}
}
结论
在路由和导航方面,Flutter 再次在效率和易用性方面大放异彩。 希望这个简短的教程有助于理解这项新技术。