我们先编写一个简单的demo:
1
2
3
4
5
6
7
8
9 1import 'package:flutter/material.dart';
2
3void main() => runApp(Center(
4 child: Text(
5 'Hello, world!',
6 textDirection: TextDirection.ltr,
7 ),
8));
9
-
import: 和Java中一样,导包
- function:见系列四
- 涉及的Widget对象:
-
Center对象:对于子Widget有约束,即它的子Widget是居中的
* Text:可以类比TextView,第一个参数就是文本内容,textDirection参数指定文本内容是从左到右显示(ltr)还是从右往左(rtl)显示
截图:
-
我们来看一个更加优雅的demo:
-
编写我们的main函数:
1
2
3
4
5
6 1void main() {
2 runApp(MaterialApp(
3 home: MyScaffold(),
4 ));
5}
6
- 将一个MaterialApp对象作为参数传递到了runApp函数中,runApp的作用我们之前的篇章提到过:传入到runApp的widget对象会被作为Widget tree的根节点,并且会显示在屏幕上。
* MaterialApp对象:它实际上也是一个Widget,它是用来实现Google的Material Design的便捷Widget,即它里面会封装一些其他的widget。一个不恰当的比方就是有点类似Application的主题。
* home属性:进入程序后显示的第一个页面
* Dart语言本身相关:
a. 如何创建对象?像Java一样通过new关键字;像Kotlin一样,省略new关键字。这两种方式都ok
b. 关于可选的有名参数(optional named parameter),同样可以参考系列四
1
2 1* 编写MyScaffold类:
2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 1class MyScaffold extends StatelessWidget {
2 @override
3 Widget build(BuildContext context) {
4 return Material(
5 child: Column(
6 children: <Widget>[
7 MyAppBar(
8 title: Text(
9 'Example title',
10 style: Theme.of(context).primaryTextTheme.title,
11 ),
12 ),
13 Expanded(
14 child: Center(
15 child: Text('我是content,我在中间'),
16 ),
17 ),
18 ],
19 ),
20 );
21 }
22}
23
24class MyAppBar extends StatelessWidget {
25 final Widget title;
26
27 MyAppBar({this.title});
28
29 @override
30 Widget build(BuildContext context) {
31 return Container(
32 height: 56.0,
33 padding: const EdgeInsets.symmetric(horizontal: 8.0),
34 decoration: BoxDecoration(color: Colors.blue[500]),
35 child: Row(
36 children: <Widget>[
37 IconButton(
38 icon: Icon(Icons.menu),
39 onPressed: null,
40 ),
41 Expanded(
42 child: title,
43 ),
44 IconButton(icon: Icon(Icons.search), onPressed: null)
45 ],
46 ),
47 );
48 }
49}
50
从MyScaffold中看起:
-
Material:这个就是home页面的根Widget
* Column:设计理念来自于web中弹性盒子模型,类比到Android中来:就是orientation=vertical的LinearLayout;与之对应的就是Row,它是orientation=horizontal的LinearLayout。
* Expanded:这个对象可以类比LinearLayout中的weight属性的作用,那么如何设置权重值呢?
1
2
3
4
5
6
7
8 1 class Expanded extends Flexible {
2 const Expanded({
3 Key key,
4 int flex = 1,
5 @required Widget child,
6 }) : super(key: key, flex: flex, fit: FlexFit.tight, child: child);
7 }
8
通过flex来设置,默认是1
MyAppBarLayout中:
- Container:这个只能勉勉强强比喻成ViewGroup。这里用的属性有height、padding,这俩都好理解;至于这个decoration,可以理解成background.
* IconButton:类比成ImageButton/ImageView.这里需要注意的是一个onPressed属性,很明显我们可以在这指定点击事件的处理函数.
最终的运行效果为:
-
注意pubspec.yaml文件中
1
2
3 1 flutter:
2 uses-material-design: true
3
这个文件就相当于我们build.gradle文件一样,这里可以指定依赖、版本号等
-
在demo2中,MyScaffold、MyAppBar,这些都是我们自定义的Widget,实际上这些都有对应的Material组件已经定义好了。请看demo3:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 1void main() {
2 runApp(MaterialApp(
3 home: MaterialHome(),
4 ));
5}
6
7class MaterialHome extends StatelessWidget {
8 @override
9 Widget build(BuildContext context) {
10 return Scaffold(
11 appBar: AppBar(
12 leading: IconButton(icon: Icon(Icons.menu), onPressed: null),
13 title: Text("I'm title"),
14 actions: <Widget>[
15 IconButton(
16 icon: Icon(Icons.search),
17 onPressed: null,
18 )
19 ],
20 ),
21 body: Center(
22 child: Text("I'm content and in center"),
23 ),
24 floatingActionButton: FloatingActionButton(
25 onPressed: null,
26 child: Icon(Icons.add),
27 ),
28 );
29 }
30}
31
- Scaffold:脚手架,它实现了基本Material布局
- FloatingActionButton:就是我们常见的FAB 运行效果图:
-
下面我想实现对按钮点击的响应:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 1class MaterialHome extends StatelessWidget {
2 @override
3 Widget build(BuildContext context) {
4 return Scaffold(
5 appBar: AppBar(
6 leading: IconButton(icon: Icon(Icons.menu), onPressed: null),
7 title: Text("I'm title"),
8 actions: <Widget>[
9 IconButton(
10 icon: Icon(Icons.search),
11 onPressed: onSearchClick,
12 )
13 ],
14 ),
15 body: Center(
16 child: Text("I'm content and in center"),
17 ),
18 floatingActionButton: FloatingActionButton(
19 onPressed: onFabClick,
20 child: Icon(Icons.add),
21 ),
22 );
23 }
24
25 void onSearchClick() {
26 // 可以使用print函数输出日志
27 print("search button clicked");
28 }
29
30 void onFabClick() {
31 print("fab clicked");
32 }
33}
34
注意两个onPressed属性的赋值:直接将我们定义好的函数名传递过去。在Function系列说过,在Dart语言中,所有的函数都是一个对象,它的类型为Function。点击按钮,我们就可以在控制台看到日志输出了,证明我们事件处理函数得到调用了。
参考文献:《Flutter Tutorial》