Flutter项目初探

创建Flutter应用

可以通过命令行输入下面的命令创建一个flutter项目:

1
flutter create first_flutter_app

注意,项目名不支持特殊符号和大写,只能使用下划线进行分隔。

创建成功后通过相应的开发工具打开项目即可。

示例程序分析

示例程序中,主要Dart代码在lib/main.dart文件中,这个文件是lutter启动的入口文件,包含main()函数。

导入包

下面代码的作用是导入Material UI组件库。Material是一种标准的移动端和web端的视觉设计语言, Flutter默认提供了一套丰富的Material风格的UI组件。

1
import 'package:flutter/material.dart';

应用入口

Flutter 应用中main函数为应用程序的入口。main函数中调用了runApp 方法,它的功能是启动Flutter应用。runApp接受一个Widget参数。

1
2
3
void main() {
runApp(MyApp());
}

在Flutter中,大部分都是widget,包括对齐(alignment)、填充(padding)和布局(layout)等功能,都是以widget的形式提供。

应用结构

1
2
3
4
5
6
7
8
9
10
11
12
13
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}

MyApp类代表当前的Flutter应用,它继承了StatelessWidget类,这也就意味着应用本身也是一个widget。

在Flutter开发中,我们可以继承自StatelessWidget或者StatefulWidget来创建自己的Widget类。

  • StatelessWidget:没有状态改变的Widget,通常仅用来展示;
  • StatefulWidget:需要保存状态,并且可能出现状态改变的Widget;

widget的主要工作是提供一个build()方法来描述如何构建UI界面(通常是通过组合、拼装其它基础widget)。

build()方法会在以下情况下执行:

  • 当StatelessWidget第一次被插入到Widget树中时(也就是第一次被创建时;
  • 当父Widget发生改变时,子Widget会被重新构建;
  • 如果我们的Widget依赖InheritedWidget的一些数据,InheritedWidget数据发生改变时;

首页

1
2
3
4
5
6
7
8
9
10
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
...
}

MyHomePage是应用的首页,它继承自StatefulWidget类,表示它是一个有状态的组件(Stateful widget)。

一个Stateful widget至少由两个类组成:

  • 一个StatefulWidget类;
  • 一个 State类; StatefulWidget类本身是不变的,但是State类中持有的状态在widget生命周期中可能会发生变化;

State类

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
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;

void _incrementCounter() {
setState(() {

_counter++;
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

当按钮点击时,会调用_incrementCounter方法,先自增_counte计数,然后调用setState方法。

setState方法的作用是通知Flutter框架,有状态发生了改变,Flutter框架收到通知后,会执行build方法来根据新的状态重新构建界面, Flutter 对此方法做了优化。

Scaffold 是 Material库中提供的页面脚手架,它提供了默认的导航栏、标题和包含主屏幕widget树的body属性,body是页面的内容部分。

核心逻辑

整个示例程序的核心逻辑是,当右下角的floatingActionButton按钮被点击之后,会调用_incrementCounter方法。在_incrementCounter方法中,首先会自增_counter计数器(状态),然后setState会通知Flutter框架状态发生变化,接着,Flutter框架会调用build方法以新的状态重新构建UI,最终显示在设备屏幕上。