One of the most fundamental aspects of a mobile app is for the user to be able to move between different pages. Luckily for us, Flutter makes creating routes and moving between screens incredibly easy, especially when compared to many front-end solutions.
移动应用程序最基本的方面之一是使用户能够在不同页面之间移动。 对我们来说幸运的是,Flutter使创建路线和在屏幕之间移动变得异常容易,特别是与许多前端解决方案相比。
项目文件设置 (Project File Setup)
For our example, we’re just going to have 4 screens, our main.dart
file, and break the navbar into its own file.
对于我们的示例,我们将只有4个屏幕,即我们的main.dart
文件,并将导航栏分成自己的文件。
* screens 📂
* account_screen.dart
* balance_screen.dart
* transfer_screen.dart
* welcome_screen.dart
* main.dart
* navbar.dart
命名路线 (Naming Routes)
While you would want to break each route into its own file in most cases, we’ll put them in our main.dart
for now.
尽管在大多数情况下,您希望将每条路由分成自己的文件,但我们现在将它们放置在main.dart
中。
In our MaterialApp
we can set the routes
map, which is a list of key/value pairs. Each item in this map links a string value to a callback function that returns the page we want rendered. The point of this is to speed up development by letting us toss around something like 'welcome_screen'
whenever we need a new page, instead of the full (context) => WelcomeScreen()
.
在我们的MaterialApp
我们可以设置routes
图,这是键/值对的列表。 此映射中的每个项目都将字符串值链接到回调函数,该回调函数返回我们要呈现的页面。 这样做的目的是通过在需要新页面'welcome_screen'
不是完整的(context) => WelcomeScreen()
,让我们在'welcome_screen'
类'welcome_screen'
东西之间折腾来加快开发速度。
To set our home page we can either use the MaterialApp
’s home
property or the initialRoute
property. They effectively do the same thing but home
takes the class itself, like WelcomeScreen()
, and initialRoute
takes the key from our routes
map. You can’t use both since that confuses the compiler.
要设置主页,我们可以使用MaterialApp
的home
属性或initialRoute
属性。 他们有效地执行了相同的操作,但是home
本身接受了类,例如WelcomeScreen()
,而initialRoute
从我们的routes
图中获取了键。 您不能同时使用两者,因为这会使编译器感到困惑。
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()
});
}
}
That works fine, but you may end up typing each of these routes often and just using strings will make it hard to debug when you make the slightest typo. Instead it would make our code a bit less fragile to store each key in a static id variable in each class and just access that id. This will also give us the benefit of VSCode’s IntelliSense and help figuring out why a page may be unavailable.
效果很好,但是您可能最终会经常键入这些路由中的每一个,而使用字符串将使您在进行丝毫打字错误时难以调试。 取而代之的是,将每个键存储在每个类的静态id变量中并仅访问该id,将使我们的代码不那么脆弱。 这也将使我们受益于VSCode的IntelliSense,并有助于弄清为什么页面不可用。
Each screen in our example is the same, beside the id and the text widget. We’re also setting out bottom navbar to a widget that we’ll create later.
在我们的示例中,每个屏幕都相同,除了id和text小部件。 我们还将底部导航栏设置为稍后将创建的小部件。
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'),
),
);
}
}
Now we can replace our string with each screen’s id. Notice that we’re accessing it without actually calling the class itself.
现在,我们可以将字符串替换为每个屏幕的ID。 注意,我们在访问它时并未实际调用类本身。
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()
});
}
}
推和弹出 (Push and Pop)
Unlike with front-end web development, mobile routing is based on ‘stacking’ screens on top of each other. When we navigate from the welcome screen to the account screen, we’re not really changing pages but adding our account screen onto our stack, thus covering the previous page. To go back to the welcome screen, we would just need to destroy, or pop
off, the uppermost layer revealing the already rendered page beneath it.
与前端Web开发不同,移动路由基于彼此叠加的“堆叠”屏幕。 当我们从欢迎屏幕导航到帐户屏幕时,我们实际上并不是在更改页面,而是将帐户屏幕添加到堆栈中,从而覆盖了上一页。 要返回到欢迎屏幕,我们只需要破坏或pop
最上层,以显示其下面已渲染的页面。
There are quite a few different methods on Navigator
to do this, which you can fully explore here. The main two we need are pushNamed
to add to our stack and pop
to remove the latest layer. pop
just needs our build’s context
and push
methods needs the context
and the page’s key we’ve setup in our routes.
Navigator
上有很多不同的方法可以执行此操作,您可以在此处充分探索。 我们需要的主要两个是pushNamed
以添加到堆栈中,然后pop
以删除最新层。 pop
仅需要我们构建的context
而push
方法则需要context
和我们在路由中设置的页面密钥。
Any method appended with Named
is for when we’ve set up our routes in the MaterialApp
, otherwise you could pass in the callback itself instead of our keys.
当我们在MaterialApp
设置路线时,将使用Named
附加的任何方法,否则您可以传入回调本身而不是键。
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)),
],
),
);
}
}
结论 (Conclusion)
Yet again when it comes to routing and navigation Flutter really shines in efficiency and ease of use. Hopefully this short tutorial was helpful in understanding this new technology.
再有,在路由和导航方面,Flutter确实在效率和易用性方面大放异彩。 希望这篇简短的教程对理解这项新技术有所帮助。
翻译自: https://www.digitalocean.com/community/tutorials/flutter-navigation