上一篇介绍了Flutter 安装配置 相关内容,接下来这一篇先新来一个示例介绍一下Flutter项目的基本结构。
新建项目
- 打开编辑器(这里以IntelliJ IDEA为例,Android Studio基本一致)
- File>New>Project,选择Flutter 项目
Next 填写项目相关内容,Organization 这里通常建议是域倒写.
填写完毕点击FINISH,将会自动生成一个示例项目。
- 打开模拟器:点击上方菜单栏,选择模拟器(这里选择iOS 模拟器)
点击后,iOS模拟器会启动,但是还需要再选择设备
启动后界面如下:
现在可以点击菜单栏上方运行项目,输出结果如下
Launching lib/main.dart on iPhone 11 in debug mode...
Running Xcode build...
Xcode build done. 46.6s
Debug service listening on ws://127.0.0.1:61858/TQG1yn-Cjq0=/ws
Syncing files to device iPhone 11...
现在一个简单的项目就运行完毕。
第一次真机运行的时候可能会需要更多的等待时间,但是接下来你就可以使用热重载(hot reload)功能,热重载可以在运行时更新预览。
项目目录
├── README.md
├── android
├── build
├── hello_world.iml
├── ios
├── lib
├── pubspec.lock
├── pubspec.yaml
└── test
主要关注以下几个文件/目录:
文件/目录 | 描述 |
---|---|
android | android 平台相关代码 |
ios | iOS平台相关代码 |
lib | flutter 应用代码,编写的代码在此目录 |
test | 测试相关代码 |
pubspec.yaml | 管理 Flutter 应用程序的 assets(资源,如图片、package等) |
代码介绍
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
// MyApp 不需要做状态管处理,此组件继承StatelessWidget 即可
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,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState(); // 重写
}
// 状态类必须继承自 State类
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0; // 定义一个变量 _counter 作为计数器变量,调用 setState 方法来控制这个变量的值变化
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(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have clicked the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
- 代码第一行引入了 material.dart 包,使用此包,模板代码创建了一个具有 Material Design 风格的应用( Material 是一种移动端和网页端通用的视觉设计语言, Flutter 提供了丰富的 Material 风格的 widgets。
void main() => runApp(MyApp());
主函数(main)使用了 (=>
) 符号,这是 Dart 中单行函数或方法的简写,等同于下属代码
flutter 项目都需要在开始的时候执行main 函数,使用runApp() 函数可以讲给定的根组件填满整个屏幕。(如果不调用runApp() 函数,项目也可以正常运行,但是屏幕上什么都不会显示。void main() {
runApp(MyApp());
}
状态管理
- 该应用程序继承了
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 方法,代码如下:
@override
_MyHomePageState createState() => _MyHomePageState();
Scaffold
是 Material 库中提供的一个 widget,它提供了默认的导航栏、标题和包含主屏幕 widget 树的 body 属性。- 现在在Scaffold 中添加 backgroundColor: Colors.amber
保存代码后,页面应该会自动刷新,结果如下:Widget build(BuildContext context) {
return Scaffold(
...
backgroundColor: Colors.amber,
...
);
}
- 现在在Scaffold 中添加 backgroundColor: Colors.amber
如果自动保存后页面没有自动重载,可以点击下图红圈中按钮查看更新后结果。
- 一个 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 会将依赖包安装到你的项目。你应该会在控制台中看到以下内容:
Running "flutter pub get" in hello_world... 0.6s
Process finished with exit code 0
在执行 Pub get
命令时会自动生成一个名为 pubspec.lock
文件,这里包含了你依赖 packages 的名称和版本。
然后在lib/main.dart 代码第二行加入 import ‘package:english_words/english_words.dart’;
如果你尝试热重载,则可能会看到一条警告,考虑重新启动当前应用:
Reloading…
Some program elements were changed during reload but did not run when the view was reassembled;
you might need to restart the app (by pressing “R”) for the changes to have an effect.
因为重启应用之后就可以生效,故这可能是误报。现在只需点击build 按钮重新build。
修改后的代码如下:
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
final wordPair = WordPair.random();
return Scaffold(
...
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have clicked the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
Text(
'Words Pair:' + wordPair.asPascalCase,
),
],
),
),
...
}
}
此时点击右下角的按钮,数字会增加,单词对也会更新。