每日一言:与其担心未来,不如现在好好努力。这条路上,只由奋斗才能给你安全感。不要轻易把梦想寄托在某个人身上,也不要太在乎身旁的耳语,因为未来是你自己的,只有你自己才能给你自己最大的安全感。
原文链接:http://liuwangshu.cn/flutter/primer/5-material-components.html
关联系列:Flutter基础(一)移动开发跨平台技术的百家争鸣
Flutter基础(二)Flutter开发环境搭建和Hello World
Flutter基础(三)Dart快速入门
Flutter基础(四)开发Flutter应用前需要掌握的Basics Widget
前言
在上一篇文章Flutter基础(四)开发Flutter应用前需要掌握的Basics Widget,我们学习了Basics Widget,除了Basics Widget,我们还需要了解Material Components,也就是Material组件。它提供了实现Material Design准则的视觉、行为和动作的Widget。由于Material组件比较多,而这些组件又十分重要,因此分为多篇进行介绍。
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。