前言
在上一篇文章 Flutter 基础(四)开发 Flutter 应用前需要掌握的 Basics Widget,我们学习了 Basics Widget,除了 Basics Widget,我们还需要了解 Material Components,也就是 Material 组件。它提供了实现 Material Design 准则的视觉、行为和动作的 Widget。
官方将 Material 组件分为为几个类型:
- 应用程序结构和导航
- Button
- 输入和选择
- 对话框,警告弹框和面板
- 信息显示
- 布局
主要介绍应用程序结构和导航,会分为两篇文章进行介绍,这一篇介绍应用程序结构和导航分类中的 MaterialApp、Scaffold、AppBar。
1.MaterialApp
说到 Material 组件,不得不提到 MaterialApp,它包含了许多 Widget,这些 Widget 通常是实现 Material Design 的应用程序所必需的。
MaterialApp 在此前的文章都用过,简单的使用这里就不介绍了,这里主要介绍下路由。
移动 App 中通常通过全屏元素 “屏幕” 或 “页面” 来显示内容。在 Flutter 中,这些元素被称为 route(路由),它们由 Navigator 管理。Navigator 不仅管理了一堆 route,还提供管理堆栈的方法 Navigator.push 和 Navigator.pop,通过路由对象的进出栈来控制页面的跳转。
flutter 路由的使用方式主要有两种,一种是新建路由,一种是注册路由。我们分别用这两种方式写例子:
首屏是第一个界面,通过第一个界面的按钮跳转到第二页,点击第二页的按钮回到第一页。
1.1 新建路由
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material Components',
home: FirstPage(),
);
}
}
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('第一页'),
),
body: Padding(
padding: EdgeInsets.all(30.0),
child: RaisedButton(
child: Text('跳转到第二页'),
onPressed: () {
Navigator.push(//1
context,
MaterialPageRoute(builder: (context) => SecondPage()),
);
},
),
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('第二页'),
),
body: Padding(
padding: EdgeInsets.all(30.0),
child: RaisedButton(
child: Text('回到上一页'),
onPressed: () {
Navigator.pop(context);//2
}),
),
);
}
}
注释 1 处调用了 Navigator.push,将新建的路由添加到 Navigator 管理的 route 堆栈的栈顶,这个路由我们可以自定义,但是建议使用 MaterialPageRoute,它是一个模态路由,可以自适应各个平台进行页面替换,并提供了相应的页面切换动画。在 Android 平台时,页面进入动画是向上滑动并淡出,退出是相反的动画,如果是在 iOS 平台 ,页面进入动画是从右侧滑入,退出是相反的动画。
点击’跳转到第二页’按钮时会跳转到 SecondPage。注释 2 处的 Navigator.pop 用于弹出 route 堆栈最顶层的 Route。效果如下两个图所示。
1.2 注册路由
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material Components',
home: FirstPage(),
routes: <String, WidgetBuilder>{//1
'/first': (BuildContext context) => FirstPage(),
'/second': (BuildContext context) => SecondPage(),
},
initialRoute: '/first' ,
);
}
}
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('第一页'),
),
body: Padding(
padding: EdgeInsets.all(30.0),
child: RaisedButton(
child: Text('跳转到第二页'),
onPressed: () {
Navigator.pushNamed(context, '/second');//2
},
),
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('第二页'),
),
body: Padding(
padding: EdgeInsets.all(30.0),
child: RaisedButton(
child: Text('回到上一页'),
onPressed: () {
Navigator.of(context).pop();
}),
),
);
}
}
通过注释 1 处的 routes 用于初始化一个路由列表,当推送路由时,将在 routes 中查找路径名称,如果名称存在,则关联的 WidgetBuilder 用于构造 MaterialPageRoute。注释 2 处的 Navigator.pushNamed 和 Navigator.push 作用类似,只不过 pushNamed 的参数为路由的名称。
2. Scaffold
Scaffold 同样属于 Material 组件,它实现了 Material Design 的基本布局结构,因此它经常会作为 MaterialApp 的子 Widget, Scaffold 会自动填充可用的空间,这通常意味着它将占据整个窗口或屏幕,并且 Scaffold 会自动适配屏幕。我们的布局就是在 Scaffold 中进行编写的。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Scaffold示例'),
),
body: Padding(
padding: EdgeInsets.all(30.0),
child: Text('Scaffold'),
),
bottomNavigationBar: BottomAppBar(
child: Container(height: 50),
),
drawer: Drawer(
child: Center(
child: Text('抽屉'),
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
),
),
);
}
}
Scaffold 的属性有很多,例子中用了几个属性:
- appBar:用于设置顶部的标题栏。
- body:显示 Scaffold 的主要内容。
- bottomNavigationBar:用于设置 Scaffold 的底部导航栏,
- drawer:用于设置抽屉效果。
- floatingActionButton:用于设置位于右下角的按钮。
效果如下所示:
可以看到在 AppBar 上有个抽屉的按钮,点击按钮就会滑出抽屉。
3. AppBar
AppBar 由 toolbar 和其他的可选 Widget 组成,比如 TabBar 和 FlexibleSpaceBar。
AppBar 会在顶部显示 leading、title、actions 等内容,底部 bottom 通常显示 TabBar,下图展示了这些内容的位置分布。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyScaffld(),
);
}
}
class MyScaffld extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('AppBar示例'),
leading: FlutterLogo(colors: Colors.lightGreen),
actions: <Widget>[
IconButton(
icon: Icon(Icons.share),
onPressed: () {
print('添加按钮');
},
),
],
),
);
}
}
这次没有把所有代码写在 MyApp 类中,而是将 Scaffld 的定义放在了 MyScaffld 类中。
上面代码的 Widget 树如下所示,遵守 Material Design 准则的 flutter 应用的 Widget 树大致也是如此。
总结
本文总结了 Material 组件中的三种 Widget,可以说它们是使用 Material 组件时最常使用的 Widget,常用到我们可能会忽略它们。由于篇幅原因,会在下一篇介绍 Material 组件的其他 Widget。
文章评论