新建一个Flutter项目,目录结构如下:
    1638327485(1).png
    需要关注的几个目录和文件:

    • android

    Android应用信息配置目录,诸如权限、原生交互、打包配置等,需要在该文件夹中编辑。

    • ios

    同android,是ios的配置目录,权限配置、打包等都需要在该文件夹中执行。

    • lib

    Flutter的dart代码目录,所有的Flutter代码都必须在该目录下。

    • web

    同android和ios,是生成web应用的配置目录。

    • pubspec.yaml

    Flutter项目的配置文件,可配置引用的第三方插件、字体,本地(包内)的静态资源以及应用版本。

    在lib目录下会默认新建一个main.dart文件,该文件为项目的唯一入口,在里边执行了一个main方法:

    1. void main() {
    2. runApp(const MyApp());
    3. }
    1. 其中MyApp是一个自定义的Widget,一般来说需要返回一个MaterialApp,来看一下demo项目的写法:
    1. import 'package:flutter/material.dart';
    2. void main() {
    3. runApp(const MyApp());
    4. }
    5. class MyApp extends StatelessWidget {
    6. const MyApp({Key? key}) : super(key: key);
    7. // This widget is the root of your application.
    8. @override
    9. Widget build(BuildContext context) {
    10. return MaterialApp(
    11. title: 'Flutter Demo',
    12. theme: ThemeData(
    13. // This is the theme of your application.
    14. //
    15. // Try running your application with "flutter run". You'll see the
    16. // application has a blue toolbar. Then, without quitting the app, try
    17. // changing the primarySwatch below to Colors.green and then invoke
    18. // "hot reload" (press "r" in the console where you ran "flutter run",
    19. // or simply save your changes to "hot reload" in a Flutter IDE).
    20. // Notice that the counter didn't reset back to zero; the application
    21. // is not restarted.
    22. primarySwatch: Colors.blue,
    23. ),
    24. home: const MyHomePage(title: 'Flutter Demo Home Page'),
    25. );
    26. }
    27. }
    28. class MyHomePage extends StatefulWidget {
    29. const MyHomePage({Key? key, required this.title}) : super(key: key);
    30. // This widget is the home page of your application. It is stateful, meaning
    31. // that it has a State object (defined below) that contains fields that affect
    32. // how it looks.
    33. // This class is the configuration for the state. It holds the values (in this
    34. // case the title) provided by the parent (in this case the App widget) and
    35. // used by the build method of the State. Fields in a Widget subclass are
    36. // always marked "final".
    37. final String title;
    38. @override
    39. State<MyHomePage> createState() => _MyHomePageState();
    40. }
    41. class _MyHomePageState extends State<MyHomePage> {
    42. int _counter = 0;
    43. void _incrementCounter() {
    44. setState(() {
    45. // This call to setState tells the Flutter framework that something has
    46. // changed in this State, which causes it to rerun the build method below
    47. // so that the display can reflect the updated values. If we changed
    48. // _counter without calling setState(), then the build method would not be
    49. // called again, and so nothing would appear to happen.
    50. _counter++;
    51. });
    52. }
    53. @override
    54. Widget build(BuildContext context) {
    55. // This method is rerun every time setState is called, for instance as done
    56. // by the _incrementCounter method above.
    57. //
    58. // The Flutter framework has been optimized to make rerunning build methods
    59. // fast, so that you can just rebuild anything that needs updating rather
    60. // than having to individually change instances of widgets.
    61. return Scaffold(
    62. appBar: AppBar(
    63. // Here we take the value from the MyHomePage object that was created by
    64. // the App.build method, and use it to set our appbar title.
    65. title: Text(widget.title),
    66. ),
    67. body: Center(
    68. // Center is a layout widget. It takes a single child and positions it
    69. // in the middle of the parent.
    70. child: Column(
    71. // Column is also a layout widget. It takes a list of children and
    72. // arranges them vertically. By default, it sizes itself to fit its
    73. // children horizontally, and tries to be as tall as its parent.
    74. //
    75. // Invoke "debug painting" (press "p" in the console, choose the
    76. // "Toggle Debug Paint" action from the Flutter Inspector in Android
    77. // Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
    78. // to see the wireframe for each widget.
    79. //
    80. // Column has various properties to control how it sizes itself and
    81. // how it positions its children. Here we use mainAxisAlignment to
    82. // center the children vertically; the main axis here is the vertical
    83. // axis because Columns are vertical (the cross axis would be
    84. // horizontal).
    85. mainAxisAlignment: MainAxisAlignment.center,
    86. children: <Widget>[
    87. const Text(
    88. 'You have pushed the button this many times:',
    89. ),
    90. Text(
    91. '$_counter',
    92. style: Theme.of(context).textTheme.headline4,
    93. ),
    94. ],
    95. ),
    96. ),
    97. floatingActionButton: FloatingActionButton(
    98. onPressed: _incrementCounter,
    99. tooltip: 'Increment',
    100. child: const Icon(Icons.add),
    101. ), // This trailing comma makes auto-formatting nicer for build methods.
    102. );
    103. }
    104. }
    1. 将以上代码分为几个部分解读:
    • 第1行

    import ‘package:flutter/material.dart’;
    表示引入material包,material是一个UI包,几乎所有的页面都需要基于该包来开发。

    • 第3-5行

    执行main方法,这是程序的入口。

    • 第7-30行

    新建一个无状态的widget,继承自StatelessWidget,重写build方法,在其中返回一个MaterialApp,配置它的主页为MyHomePage()。

    • 第32-48行

    实现一个有状态的MyHomePage,继承自StatefulWidget,重写createState方法,返回一个_MyHomePageState()。

    • 第50-115行

    实现_MyHomePageState,在build中构建UI,其中54-61表示通过setState更新数值,只有通过setState方法更新值,才能刷新UI的显示。Scaffold是一个常用的脚手架,几乎所有页面都基于他来编写,类似android中的activity。