上一篇介绍了Flutter 安装配置 相关内容,接下来这一篇先新来一个示例介绍一下Flutter项目的基本结构。

新建项目

  1. 打开编辑器(这里以IntelliJ IDEA为例,Android Studio基本一致)
  2. File>New>Project,选择Flutter 项目

截屏2020-06-21 上午9.27.06.png
Next 填写项目相关内容,Organization 这里通常建议是域倒写.
截屏2020-06-21 上午9.29.01.png
填写完毕点击FINISH,将会自动生成一个示例项目。
截屏2020-06-21 上午9.29.24.png

  1. 打开模拟器:点击上方菜单栏,选择模拟器(这里选择iOS 模拟器)

截屏2020-06-21 上午9.30.00.png
点击后,iOS模拟器会启动,但是还需要再选择设备
截屏2020-06-21 上午9.33.37.png

启动后界面如下:

截屏2020-06-21 上午9.33.50.png

现在可以点击菜单栏上方运行项目,输出结果如下

  1. Launching lib/main.dart on iPhone 11 in debug mode...
  2. Running Xcode build...
  3. Xcode build done. 46.6s
  4. Debug service listening on ws://127.0.0.1:61858/TQG1yn-Cjq0=/ws
  5. Syncing files to device iPhone 11...

现在一个简单的项目就运行完毕。
Simulator Screen Shot - iPhone 11 - 2020-06-21 at 09.35.48.png
第一次真机运行的时候可能会需要更多的等待时间,但是接下来你就可以使用热重载(hot reload)功能,热重载可以在运行时更新预览。


项目目录

  1. ├── README.md
  2. ├── android
  3. ├── build
  4. ├── hello_world.iml
  5. ├── ios
  6. ├── lib
  7. ├── pubspec.lock
  8. ├── pubspec.yaml
  9. └── test

主要关注以下几个文件/目录:

文件/目录 描述
android android 平台相关代码
ios iOS平台相关代码
lib flutter 应用代码,编写的代码在此目录
test 测试相关代码
pubspec.yaml 管理 Flutter 应用程序的 assets(资源,如图片、package等)

代码介绍

  1. import 'package:flutter/material.dart';
  2. void main() => runApp(MyApp());
  3. // MyApp 不需要做状态管处理,此组件继承StatelessWidget 即可
  4. class MyApp extends StatelessWidget {
  5. // This widget is the root of your application.
  6. @override
  7. Widget build(BuildContext context) {
  8. return MaterialApp(
  9. title: 'Flutter Demo',
  10. theme: ThemeData(
  11. primarySwatch: Colors.blue,
  12. visualDensity: VisualDensity.adaptivePlatformDensity,
  13. ),
  14. home: MyHomePage(title: 'Flutter Demo Home Page'),
  15. );
  16. }
  17. }
  18. class MyHomePage extends StatefulWidget {
  19. MyHomePage({Key key, this.title}) : super(key: key);
  20. final String title;
  21. @override
  22. _MyHomePageState createState() => _MyHomePageState(); // 重写
  23. }
  24. // 状态类必须继承自 State类
  25. class _MyHomePageState extends State<MyHomePage> {
  26. int _counter = 0; // 定义一个变量 _counter 作为计数器变量,调用 setState 方法来控制这个变量的值变化
  27. void _incrementCounter() {
  28. setState(() {
  29. _counter++;
  30. });
  31. }
  32. @override
  33. Widget build(BuildContext context) {
  34. return Scaffold(
  35. appBar: AppBar(
  36. // Here we take the value from the MyHomePage object that was created by
  37. // the App.build method, and use it to set our appbar title.
  38. title: Text(widget.title),
  39. ),
  40. body: Center(
  41. // Center is a layout widget. It takes a single child and positions it
  42. // in the middle of the parent.
  43. child: Column(
  44. mainAxisAlignment: MainAxisAlignment.center,
  45. children: <Widget>[
  46. Text(
  47. 'You have clicked the button this many times:',
  48. ),
  49. Text(
  50. '$_counter',
  51. style: Theme.of(context).textTheme.headline4,
  52. ),
  53. ],
  54. ),
  55. ),
  56. floatingActionButton: FloatingActionButton(
  57. onPressed: _incrementCounter,
  58. tooltip: 'Increment',
  59. child: Icon(Icons.add),
  60. ), // This trailing comma makes auto-formatting nicer for build methods.
  61. );
  62. }
  63. }
  • 代码第一行引入了 material.dart 包,使用此包,模板代码创建了一个具有 Material Design 风格的应用( Material 是一种移动端和网页端通用的视觉设计语言, Flutter 提供了丰富的 Material 风格的 widgets。
  • void main() => runApp(MyApp()); 主函数(main)使用了 (=>) 符号,这是 Dart 中单行函数或方法的简写,等同于下属代码
    1. void main() {
    2. runApp(MyApp());
    3. }
    flutter 项目都需要在开始的时候执行main 函数,使用runApp() 函数可以讲给定的根组件填满整个屏幕。(如果不调用runApp() 函数,项目也可以正常运行,但是屏幕上什么都不会显示。

状态管理

  • 该应用程序继承了 StatelessWidget,这将会使应用本身也成为一个 widget。在 Flutter 中,几乎所有都是 widget,包括对齐 (alignment)、填充 (padding) 和布局 (layout)。
  • Stateless widgets 是不可变的,这意味着它们的属性不能改变 —— 所有的值都是 final。
  • Stateful widgets 持有的状态可能在 widget 生命周期中发生变化,实现一个 stateful widget 至少需要两个类:
    • 1)一个 StatefulWidget 类,本身是不可变的
    • 2)一个 State 类,但是 State 类在 widget 生命周期中始终存在。


  • MyHomePage 类是一个Stateful widgets(有状态的 widget)
    • 必须继承自StatefulWidget
    • 它创建自己的状态类 —— _MyHomePageState,并将 MyHomePage 内嵌到已有的无状态的 MyApp widget。
    • 需要重写createState 方法,代码如下:
      1. @override
      2. _MyHomePageState createState() => _MyHomePageState();
  • Scaffold 是 Material 库中提供的一个 widget,它提供了默认的导航栏、标题和包含主屏幕 widget 树的 body 属性。
    • 现在在Scaffold 中添加 backgroundColor: Colors.amber
      1. Widget build(BuildContext context) {
      2. return Scaffold(
      3. ...
      4. backgroundColor: Colors.amber,
      5. ...
      6. );
      7. }
      保存代码后,页面应该会自动刷新,结果如下:

Simulator Screen Shot - iPhone 11 - 2020-06-21 at 17.41.29.png
如果自动保存后页面没有自动重载,可以点击下图红圈中按钮查看更新后结果。
截屏2020-06-21 上午9.36.57.png

  • 一个 widget 的主要工作是提供一个 build() 方法来描述如何根据其他较低级别的 widgets 来显示自己。
  • 本示例中的 body 的 widget 树中包含了一个 Center widget, Center widget 又包含一个 Text 子 widget, Center widget 可以将其子 widget 树对齐到屏幕中心。


使用第三方包

现在这个模板代码比较简单,接下来我们扩展一下,在pubspec.yaml 中,将 english_words(3.1.5 或更高版本)添加到依赖项列表,如下所示:
在 编辑器视图中查看 pubspec.yaml 文件时,点击 Pub get 会将依赖包安装到你的项目。你应该会在控制台中看到以下内容:

  1. Running "flutter pub get" in hello_world... 0.6s
  2. Process finished with exit code 0

在执行 Pub get 命令时会自动生成一个名为 pubspec.lock 文件,这里包含了你依赖 packages 的名称和版本。

然后在lib/main.dart 代码第二行加入 import ‘package:english_words/english_words.dart’;

如果你尝试热重载,则可能会看到一条警告,考虑重新启动当前应用:

  1. Reloading
  2. Some program elements were changed during reload but did not run when the view was reassembled;
  3. you might need to restart the app (by pressing R”) for the changes to have an effect.

因为重启应用之后就可以生效,故这可能是误报。现在只需点击build 按钮重新build。

修改后的代码如下:

  1. class _MyHomePageState extends State<MyHomePage> {
  2. int _counter = 0;
  3. void _incrementCounter() {
  4. setState(() {
  5. _counter++;
  6. });
  7. }
  8. @override
  9. Widget build(BuildContext context) {
  10. final wordPair = WordPair.random();
  11. return Scaffold(
  12. ...
  13. body: Center(
  14. // Center is a layout widget. It takes a single child and positions it
  15. // in the middle of the parent.
  16. child: Column(
  17. mainAxisAlignment: MainAxisAlignment.center,
  18. children: <Widget>[
  19. Text(
  20. 'You have clicked the button this many times:',
  21. ),
  22. Text(
  23. '$_counter',
  24. style: Theme.of(context).textTheme.headline4,
  25. ),
  26. Text(
  27. 'Words Pair:' + wordPair.asPascalCase,
  28. ),
  29. ],
  30. ),
  31. ),
  32. ...
  33. }
  34. }

Simulator Screen Shot - iPhone 11 - 2020-06-21 at 18.23.27.png

此时点击右下角的按钮,数字会增加,单词对也会更新。

参考链接

  1. https://flutter.cn/docs/cookbook/design/themes
  2. https://flutter.cn/docs/get-started/codelab