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 再次在效率和易用性方面大放异彩。 希望这个简短的教程有助于理解这项新技术。