- Article information - Author: Jack Lee (jcLee95)
Visit me at: https://jclee95.blog.csdn.net
Email: [email protected].
Shenzhen China
Address of this article:https://blog.csdn.net/qq_28550263/article/details/131390277
【介绍】:本文带你阅读 Flutter Demo,并全面解析其中涉及的相关知识点。
[Tip]: The effect demonstration is at the end of this article
Table of contents
1 Overview
2. Part 1: Material import and main function
2.1 Look at the code
This part of the code is:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
2.2 Import Material
import 'package:flutter/material.dart';
This line of code imports Flutter's Material library, which provides a large number of predefined UI components and styles, allowing us to quickly build applications with Material Design style.
2.2 main function
program entry
void main() {
runApp(const MyApp());
}
The main() function is the entry point to a Dart program. In this function, we call the runApp() method and pass a constant instance of the MyApp class. runApp
The () method takes the incoming Widget (component) as the root Widget of the application and starts building the Widget tree. Here, we use the custom MyApp Widget as the root Widget of the application .
runApp function
runApp()
function is the startup function of the Flutter application. It accepts a Widget parameter, which is the root Widget of the application. When the function is called runApp()
, Flutter will attach the incoming Widget to the rendering tree and start building and displaying the entire Widget tree. This function is usually called in the application's main()
function to be executed when the application starts.
runApp()
The relevant information of the function is as follows:
project | describe |
---|---|
parameter | runApp() The function accepts a Widget parameter, this Widget is usually a custom root Widget , which contains the entire UI structure of the application. |
Function | runApp() The function attaches the incoming Widget as the root Widget to the rendering tree. Then, Flutter starts to build and display the entire Widget tree, starting from the root Widget , and building each sub- Widget step by step . |
usage | runApp() Functions are typically called within an application's main() function to be executed when the application starts. |
For example:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Hello World')),
body: Center(child: Text('Welcome to my app!')),
),
);
}
}
In this example, runApp()
the function main()
is called within the function, passing an MyApp
instance of the class. MyApp
Is a custom root Widget that contains the UI structure of the entire application.
3. The second part: the stateless component MyApp class
3.1 Look at the code
This part of the code is:
class MyApp extends StatelessWidget {
const MyApp({
super.key});
// 这个 widget 是您应用程序的根。
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// 这是您应用程序的主题。
//
// 尝试一下:尝试使用 "flutter run" 运行您的应用程序。您会看到
// 应用程序具有蓝色的工具栏。然后,在不退出应用的情况下,
// 尝试将下面 colorScheme 中的 seedColor 更改为 Colors.green,
// 然后调用 "hot reload"(保存更改或按下 Flutter 支持的 IDE 中的 "hot
// reload" 按钮,或者如果您使用了命令行启动应用程序,则按 "r")。
//
// 注意计数器没有重置为零;应用程序状态在重新加载期间不会丢失。
// 要重置状态,请使用热重启代替。
//
// 这对代码也同样适用,而不仅仅是值:大多数代码更改都可以
// 通过热重载进行测试。
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter演示主页'),
);
}
}
3.2 Inherit StatelessWidget class
The following is an analysis of the Flutter code:
class MyApp extends StatelessWidget {
const MyApp({
super.key});
This code defines a MyApp
class called that inherits from StatelessWidget
. StatelessWidget
is an immutable Widget that describes a portion of the application's UI. MyApp
The class has a constructor that takes an key
optional parameter named and passes it to the superclass StatelessWidget
's constructor.
3.3 build method of StatelessWidget class
Widget build(BuildContext context) {
Here we override the method StatelessWidget
in the class build
. build
A method is a Widget
function returning a that takes a BuildContext
parameter. BuildContext
Is an object representing the position of the current Widget in the Widget tree. This method will be called when Flutter needs to build this Widget.
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter演示主页'),
);
}
}
In build
the method, we return a MaterialApp
Widget. MaterialApp
is a handy top-level widget that includes many of the basic components needed for a Material Design-style app. It accepts the following parameters:
-
title
: The title of the application, usually used for the task manager or window title. -
theme
: The theme data for the application. Here we useThemeData
the class to create a custom theme where:colorScheme
: UseColorScheme.fromSeed()
the method to generate aColors.deepPurple
color scheme based on .useMaterial3
: Set totrue
to use the Material 3 style in the application.
-
home
: The home screen widget of the application. Here, we created aMyHomePage
custom widget called and set its title to "Flutter Demo Home".
In StatelessWidget
the class, build
method is a method that describes the part of the user interface represented by this Widget. It describes the user interface by building a composition of other widgets that describe the user interface in a more concrete way. The build process recursively proceeds until the description of the user interface is fully concrete. The framework calls this method when this Widget is inserted into a given BuildContext
and when this Widget's dependencies change (for example, the that this Widget references InheritedWidget
changes).
In practice, build
the method's main purpose is to return a new Widget that describes the application's user interface. Usually, this method will contain some conditional logic to generate different widgets according to the parameters passed in or external state. This makes StatelessWidget
is a very flexible building block that can be used to create complex user interfaces.
Widget build(BuildContext context) {
// 在此处返回一个新的 Widget,描述应用程序的用户界面。
}
3.4 @override annotation in Dart language
For annotations in the dart language, you can refer to the blog post "Dart Notes: Annotations in the Dart Language"
@override
The annotation is used to indicate that the method of the subclass overrides the method of the parent class. This helps ensure that superclass methods are correctly overridden when refactoring code. The Dart analyzer will issue a warning if it is not covered correctly.
3.5 MaterialApp top-level components
MaterialApp
is a handy top-level widget that encapsulates some of the basic components required for a Material Design-style app, such as navigation, theming, and routing. It inherits from the WidgetsApp
class and provides some functionality related to Material Design. Here are MaterialApp
some of the main properties of and their explanations:
Attributes | type | Defaults | describe | reference link |
---|---|---|---|---|
title |
String | ‘’ | The title of the application that will be displayed in the operating system's task switcher. | MaterialApp.title |
home |
Widget | null | The application's default page, usually the first page displayed when the application starts. | MaterialApp.home |
theme |
ThemeData | null | The application's global theme. You can define your own ThemeData objects to customize the application's colors, fonts, button styles, and more. |
MaterialApp.theme |
color |
Color | null | The primary color used by applications in the operating system interface, such as Android's task switcher. Used if not set ThemeData.primaryColor . |
MaterialApp.color |
routes |
Map<String, WidgetBuilder> | null | The application's routing table, which defines page navigation within the application. The routing table is a mapping of strings to WidgetBuilder, where the string represents the route name, and WidgetBuilder is a BuildContext function that accepts and returns a Widget. |
MaterialApp.routes |
initialRoute |
String | null | The initial route name for the application. If set initialRoute , this route will be navigated to on startup instead of using home the attribute. |
MaterialApp.initialRoute |
onGenerateRoute |
RouteFactory | null | A callback function used to generate routes based on the given route settings. Use this property if you need to use dynamic routing or parameterized routing in your application. | MaterialApp.onGenerateRoute |
onUnknownRoute |
RouteFactory | null | A callback function to handle routes routes not found in the table. Usually used to display a "404 Page Not Found" error page. |
MaterialApp.onUnknownRoute |
navigatorKey |
GlobalKey<NavigatorState> | null | Navigator The global key associated with the application's . Navigator Use this property if you need access from other parts of your application . |
MaterialApp.navigatorKey |
builder |
TransitionBuilder | null | A callback function that can insert a Widget on top of the application's routes. This is useful for widgets that need to be displayed application-wide, such as dialogs or overlays. | MaterialApp.builder |
localizationsDelegates |
List<LocalizationsDelegate<dynamic>> | null | A LocalizationsDelegate list that sets the application's localization resources. |
MaterialApp.localizationsDelegates |
supportedLocales |
List<Locale> | null | List of regions supported by the application. | MaterialApp.supportedLocales |
以下是一个简单的 MaterialApp
示例:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
theme: ThemeData(primarySwatch: Colors.blue),
home: MyHomePage(),
);
}
}
3.6 色彩方案:ColorScheme 类
官方文档位于:https://api.flutter.dev/flutter/material/ColorScheme-class.html
ColorScheme
是一个包含一组用于描述应用程序颜色的属性的类。它是一个不可变的对象,用于定义应用程序中使用的颜色。在 Material Design 中,ColorScheme 用于定义主题的颜色。以下是 ColorScheme
的一些常用属性:
属性 | 描述 |
---|---|
primary |
应用程序主要部分的背景颜色。例如,工具栏和浮动操作按钮。 |
primaryVariant |
主要颜色的较暗版本。 |
secondary |
应用程序次要部分的背景颜色。例如,选项卡栏。 |
secondaryVariant |
次要颜色的较暗版本。 |
surface |
卡片和抽屉等表面元素的背景颜色。 |
background |
应用程序背景颜色。 |
error |
错误状态和异常情况下使用的颜色。 |
onPrimary |
显示在主要颜色上的文本和图标的颜色。 |
onSecondary |
显示在次要颜色上的文本和图标的颜色。 |
onSurface |
显示在表面颜色上的文本和图标的颜色。 |
onBackground |
显示在背景颜色上的文本和图标的颜色。 |
onError |
显示在错误颜色上的文本和图标的颜色。 |
brightness |
应用程序的整体亮度。它是一个 Brightness 枚举,可以是 Brightness.light 或 Brightness.dark 。 |
例如:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'ColorScheme Demo',
theme: ThemeData(
colorScheme: ColorScheme(
primary: Colors.blue,
primaryVariant: Colors.blue[700],
secondary: Colors.orange,
secondaryVariant: Colors.orange[700],
surface: Colors.white,
background: Colors.white,
error: Colors.red,
onPrimary: Colors.white,
onSecondary: Colors.white,
onSurface: Colors.black,
onBackground: Colors.black,
onError: Colors.white,
brightness: Brightness.light,
),
),
home: MyHomePage(),
);
}
}
4. 第三部分:有状态组件 MyHomePage
4.1 看代码
这部分代码如下:
class MyHomePage extends StatefulWidget {
const MyHomePage({
super.key, required this.title});
// 这个 widget 是你的应用程序的主页。它是有状态的,这意味着它有一个 State 对象
// (在下面定义),其中包含影响其外观的字段。
// 这个类是 state 的配置。它保存了由父级(在本例中是 App widget)提供的值
// (在本例中是标题),并被 State 的 build 方法使用。Widget 子类中的字段总是
// 被标记为 "final"。
final String title;
State<MyHomePage> createState() => _MyHomePageState();
}
4.2 继承于 StatefulWidget 类
这段代码定义了一个名为 MyHomePage
的 StatefulWidget 类,表示该类为一个 有状态组件。
class MyHomePage extends StatefulWidget {
这一行定义了一个名为 MyHomePage
的类,它继承自 StatefulWidget
。StatefulWidget
是 Flutter 中的一种 Widget,它可以在其生命周期内保持可变状态。
const MyHomePage({
super.key, required this.title});
这是 MyHomePage
类的构造函数。它接受两个参数:
super.key
:这是传递给父类(StatefulWidget
)构造函数的可选key
参数。key
参数用于控制框架如何将新的 Widget 与先前的 Widget 关联起来。通常情况下,您不需要处理key
,除非您在处理有状态的 Widget 或需要对 Widget 树进行优化。required this.title
:这是一个必需的title
参数,它是一个字符串。required
关键字表示调用构造函数时必须提供此参数。this.title
表示将传入的参数值赋给类的title
属性。
4.3 title 属性
final String title;
这一行定义了一个名为 title
的不可变字符串属性。final
关键字表示一旦初始化后,这个属性将无法更改。
4.4 createState 方法
State<MyHomePage> createState() => _MyHomePageState();
这是 createState
方法,它是 StatefulWidget
类的必需方法。此方法用于创建与此 StatefulWidget 实例关联的状态对象。@override
关键字表示我们在这里重写了父类的方法。State<MyHomePage> createState() => _MyHomePageState();
表示我们将返回一个名为 _MyHomePageState
的新状态对象。
createState
方法是 StatefulWidget
类的核心方法,它用于创建与 StatefulWidget 实例关联的状态对象。当框架需要构建 StatefulWidget 时,它会调用此方法以创建一个新的状态对象。这个状态对象将在 StatefulWidget 的整个生命周期中保持与之关联。
@override
:这是一个元数据注解,表示我们将重写父类StatefulWidget
的方法。在这种情况下,我们重写createState
方法。这样做的目的是为了提供一个自定义的状态对象,以便在构建我们的MyHomePage
StatefulWidget 时使用。State<MyHomePage> createState()
:这是我们重写的方法。方法的返回类型是State<MyHomePage>
,表示我们将返回一个与MyHomePage
类型关联的状态对象。这个状态对象将负责管理与MyHomePage
实例相关的状态。=> _MyHomePageState();
:这是一个简化的函数体,等同于{ return _MyHomePageState(); }
。箭头函数表示我们将创建一个名为_MyHomePageState
的新状态对象,并将其作为结果返回。
要了解 createState
方法的重要性,我们需要了解 StatefulWidget 的工作原理。StatefulWidget 是一个具有可变状态的 Widget。当 StatefulWidget 的状态发生变化时,框架会重新构建 Widget 树以反映这些更改。为了实现这一点,框架需要知道如何创建与 StatefulWidget 实例关联的状态对象。这就是 createState
方法的作用:告诉框架如何创建状态对象。
在实际应用中,createState
方法通常会返回一个自定义的 State
子类,该子类包含了与 StatefulWidget 实例关联的状态数据和逻辑。这使得 StatefulWidget 可以在其生命周期内保持状态,从而实现动态 UI、响应事件和执行其他与状态相关的操作。
5. 状态类 _MyHomePageState
5.1 看代码
在上一节中,定义了一个名为 MyHomePage 的 有状态组件(继承于StatefulWidget 类)。其 createState
方法中使用了一个名为 _MyHomePageState 的 状态类,该类将在创建 MyHomePage 实例时与其关联。
_MyHomePageState 类是一个自定义的 State 子类,负责管理与 MyHomePage 实例相关的状态。它包含一个 _counter
属性,表示按下按钮的次数,以及一个 _incrementCounter
方法,用于更新 _counter
的值。它还实现了 build
方法,用于构建与 MyHomePage
实例关联的 UI。
_MyHomePageState 类的代码如下:
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// 这个对 setState 的调用告诉 Flutter 框架,这个 State 中的某些内容已经发生了变化,
// 这将导致它重新运行下面的 build 方法,以便显示可以反映更新后的值。如果我们更改了
// _counter 而没有调用 setState(),那么 build 方法将不会再次被调用,因此什么都不会发生。
_counter++;
});
}
Widget build(BuildContext context) {
// 每次调用 setState 时,例如上面的 _incrementCounter 方法所做的,
// 都会重新运行此方法。
// Flutter 框架已经过优化,以使得重新运行 build 方法变得更快,
// 因此你可以重建任何需要更新的内容,而不是必须单独更改 widget 实例。
return Scaffold(
appBar: AppBar(
// 尝试一下:尝试将这里的颜色更改为特定颜色(例如 Colors.amber?),
// 然后触发热重载以查看 AppBar 的颜色变化,而其他颜色保持不变。
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
// 这里我们从由 App.build 方法创建的 MyHomePage 对象中获取值,
// 并将其用于设置我们的 appbar 标题。
title: Text(widget.title),
),
body: Center(
// Center 是一个布局 widget。它接受一个子 widget,并将其定位
// 在父 widget 的中央。
child: Column(
// Column 也是一个布局 widget。它接受一组子 widget,并垂直排列它们。
// 默认情况下,它会自动调整自身尺寸以适应其子 widget 水平方向的尺寸,
// 并尽量与其父 widget 一样高。
// Column 具有各种属性来控制它如何调整自身尺寸以及如何定位其子 widget。
// 在这里,我们使用 mainAxisAlignment 将子 widget 垂直居中;主轴在这里
// 是垂直轴,因为 Column 是垂直的(交叉轴将是水平的)。
// 尝试一下:调用 "debug painting"(在 IDE 中选择 "Toggle Debug Paint"
//操作,或者在控制台中按 "p"),以查看每个 widget 的线框。
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'你已经按了这个按钮很多次了:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // 这个尾随逗号使得自动格式化在构建方法中更加美观。
);
}
}
_MyHomePageState 类应该继承自 State 类,并实现 build
方法以构建与 MyHomePage 实例关联的 UI。
5.2 State 类
State 类的官方文档地址为:https://api.flutter.dev/flutter/widgets/State-class.html
在Flutter中,State
类是与StatefulWidget
相关的一个重要概念。State
对象存储了一个StatefulWidget
的可变状态。当状态改变时,State
对象会通知Flutter框架重建UI。
State
类的生命周期包括以下几个阶段:
阶段 | 描述 |
---|---|
created |
当State 对象被创建时,State.initState 方法会被调用。 |
initialized |
当State 对象被创建,但还没有准备构建时,State.didChangeDependencies 在这个时候会被调用。 |
ready |
State 对象已经准备好了构建,State.dispose 没有被调用的时候。 |
defunct |
State.dispose 被调用后,State 对象不能够被构建。 |
要改变State
对象的状态,可以使用setState
方法。setState
方法接受一个回调函数,该函数对状态进行修改。当回调函数执行完毕后,Flutter框架将安排重建UI。
下面是一个简单的例子,演示了如何使用State
类和setState
方法:
class Counter extends StatefulWidget {
_CounterState createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int _count = 0;
void _incrementCounter() {
setState(() {
_count = _count + 1;
});
}
Widget build(BuildContext context) {
return Column(
children: [
Text('You have pushed the button this many times:'),
Text('$_count', style: Theme.of(context).textTheme.headline4),
ElevatedButton(
onPressed: _incrementCounter,
child: Text('Increment Counter'),
),
],
);
}
}
在这个例子中,_CounterState
类维护了一个名为_count
的状态。当用户点击按钮时,_incrementCounter
方法会被调用,使用setState
方法更新_count
的值。这将触发Flutter框架重建UI,以显示更新后的计数值。
5.3 提升按钮:ElevatedButton组件
这是 Flutter 提供的诸多按钮中的一种,其前身为 凸起按钮:RaisedButton组件,RaisedButton现在已经被废弃,官方推荐使用 ElevatedButton 替代。
关于 Flutter 的各种按钮类组件及其详细用法的更多介绍,请参考博文《Flutter 组件(三)按钮类组件》:https://blog.csdn.net/qq_28550263/article/details/131387856
F. 附录
F.1 Flutter Demo 完整源代码
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({
super.key});
// 这个 widget 是您应用程序的根。
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// 这是您应用程序的主题。
//
// 尝试一下:尝试使用 "flutter run" 运行您的应用程序。您会看到
// 应用程序具有蓝色的工具栏。然后,在不退出应用的情况下,
// 尝试将下面 colorScheme 中的 seedColor 更改为 Colors.green,
// 然后调用 "hot reload"(保存更改或按下 Flutter 支持的 IDE 中的 "hot
// reload" 按钮,或者如果您使用了命令行启动应用程序,则按 "r")。
//
// 注意计数器没有重置为零;应用程序状态在重新加载期间不会丢失。
// 要重置状态,请使用热重启代替。
//
// 这对代码也同样适用,而不仅仅是值:大多数代码更改都可以
// 通过热重载进行测试。
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter演示主页'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({
super.key, required this.title});
// 这个 widget 是你的应用程序的主页。它是有状态的,这意味着它有一个 State 对象
// (在下面定义),其中包含影响其外观的字段。
// 这个类是 state 的配置。它保存了由父级(在本例中是 App widget)提供的值
// (在本例中是标题),并被 State 的 build 方法使用。Widget 子类中的字段总是
// 被标记为 "final"。
final String title;
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// 这个对 setState 的调用告诉 Flutter 框架,这个 State 中的某些内容已经发生了变化,
// 这将导致它重新运行下面的 build 方法,以便显示可以反映更新后的值。如果我们更改了
// _counter 而没有调用 setState(),那么 build 方法将不会再次被调用,因此什么都不会发生。
_counter++;
});
}
Widget build(BuildContext context) {
// 每次调用 setState 时,例如上面的 _incrementCounter 方法所做的,
// 都会重新运行此方法。
// Flutter 框架已经过优化,以使得重新运行 build 方法变得更快,
// 因此你可以重建任何需要更新的内容,而不是必须单独更改 widget 实例。
return Scaffold(
appBar: AppBar(
// 尝试一下:尝试将这里的颜色更改为特定颜色(例如 Colors.amber?),
// 然后触发热重载以查看 AppBar 的颜色变化,而其他颜色保持不变。
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
// 这里我们从由 App.build 方法创建的 MyHomePage 对象中获取值,
// 并将其用于设置我们的 appbar 标题。
title: Text(widget.title),
),
body: Center(
// Center 是一个布局 widget。它接受一个子 widget,并将其定位
// 在父 widget 的中央。
child: Column(
// Column 也是一个布局 widget。它接受一组子 widget,并垂直排列它们。
// 默认情况下,它会自动调整自身尺寸以适应其子 widget 水平方向的尺寸,
// 并尽量与其父 widget 一样高。
// Column 具有各种属性来控制它如何调整自身尺寸以及如何定位其子 widget。
// 在这里,我们使用 mainAxisAlignment 将子 widget 垂直居中;主轴在这里
// 是垂直轴,因为 Column 是垂直的(交叉轴将是水平的)。
// 尝试一下:调用 "debug painting"(在 IDE 中选择 "Toggle Debug Paint"
//操作,或者在控制台中按 "p"),以查看每个 widget 的线框。
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'你已经按了这个按钮很多次了:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // 这个尾随逗号使得自动格式化在构建方法中更加美观。
);
}
}