004_a_StatefulWidget和State的语法结构_哔哩哔哩_bilibili
https://www.bilibili.com/video/BV1RZ421p7BL?spm_id_from=333.788.videopod.episodes&vd_source=68aea1c1d33b45ca3285a52d4ef7365f&p=152
StatelessWidget无状态小部件不能setState刷新build
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; main(){ runApp(MaterialApp( home:Widget1(key:Key("abc") ) ));//带参数key的 // runApp(const MaterialApp(home:Widget1() )); } /* class Widget1 extends StatelessWidget{ // const Widget1({ super.key });//简写 const Widget1({Key? key}):super(key: key);//初始化列表的语法方法 @override Widget build(BuildContext context) { // TODO: implement build return Text("000"); } } */ //直接输入stl快捷键 class Widget1 extends StatelessWidget { int i = 0; Widget1({super.key}); //StatelessWidget 无状态的小部件,之间在里面重写build就行了,不用像有状态的小部件StatefulWidget需要createState , // 然在里面返回State的子类对象,再build @override Widget build(BuildContext context) { print("build执行"); return Column( children: [ Text("000"), Text("111"), ElevatedButton(onPressed: (){ print("${++i}"); }, child:Text("$i") ) ], ); } }
拆分讲解
main() 函数
main(){ runApp(MaterialApp( home: Widget1(key: Key("abc")) )); }
Widget1(key: Key("abc")):将 Widget1
作为主页(home)传递给 MaterialApp,并传入了一个 key。
使用 key 有助于在 widget 重建过程中保持 widget 的标识。
StatelessWidget 的定义和特点
class Widget1 extends StatelessWidget { int i = 0; Widget1({super.key}); @override Widget build(BuildContext context) { print("build执行"); return Column( children: [ Text("000"), Text("111"), ElevatedButton( onPressed: (){ print("${++i}"); }, child: Text("$i") ) ], ); } }
Widget1
是一个继承自 StatelessWidget的无状态部件(StatelessWidget)
-
意味着它一旦被创建后,内部的数据(通常是参数)不应发生变化,且 widget 本身不会维护可变的状态。
build 方法
-
每次构建时都会执行
build
方法,并打印build执行
到控制台。 -
返回了一个
Column
,其中包含两个Text
组件和一个ElevatedButton
。 -
按钮的文本显示的是当前变量
i
的值,但由于StatelessWidget
没有setState
,修改i
后不会触发重新构建(UI 刷新),因此按钮上的文本不会改变。
为什么 StatelessWidget 无法刷新 UI
-
无状态部件(StatelessWidget)的设计理念 StatelessWidget 是用来构建那些一经创建之后就不需要根据内部状态改变而重新构建的 UI 部件。它们通常只依赖构造函数传入的数据,并在整个生命周期中保持不变。
-
不能调用 setState
-
在 StatefulWidget 中,我们可以调用
setState
方法来通知 Flutter 框架某个状态已经改变,从而重新调用build
方法刷新界面。 -
而 StatelessWidget 没有
setState
方法,所以即使你在其中修改了变量(例如i
),也不会触发build
方法的再次执行,UI 不会更新。
-
-
代码中具体表现
-
当你点击按钮时,
onPressed
回调会执行,变量i
会增加并打印新的值,但因为没有调用setState
,所以build
方法不会再次被调用。 -
结果是,按钮上显示的文本仍然保持原来的值(初始构建时的值),看不到更新后的
i
。
-
注释内容
好的,下面我会详细解释注释掉的代码部分。
注释掉的代码部分:
/* class Widget1 extends StatelessWidget{ // const Widget1({ super.key });//简写 const Widget1({Key? key}):super(key: key);//初始化列表的语法方法 @override Widget build(BuildContext context) { // TODO: implement build return Text("000"); } } */
1. Widget1 extends StatelessWidget
class Widget1 extends StatelessWidget{
-
这行代码定义了一个名为
Widget1
的类,它继承自StatelessWidget
。StatelessWidget
是一个无状态的小部件,意味着它的内容不会发生改变,并且在生命周期内不需要改变其内部状态。因此,Widget1
类的状态不依赖于外部变化。
2. 构造函数:简写和初始化列表
// const Widget1({ super.key });//简写 const Widget1({Key? key}):super(key: key);//初始化列表的语法方法
这两行代码分别展示了 Widget1
类构造函数的两种写法:
-
简写方式:
const Widget1({ super.key });
这里使用了 Dart 2.17 引入的简写语法,等价于下面的方式,简化了构造函数的写法。
super.key
表示调用父类StatelessWidget
的构造函数,并将key
参数传递给它。 -
初始化列表的语法方法:
const Widget1({Key? key}): super(key: key);
这里定义了构造函数
Widget1
,它接受一个可选的Key? key
参数。Key
是 Flutter 中用来标识 widget 的标识符,通常用于在 widget 树重建时区分不同的 widget。通过super(key: key)
,这个key
参数会传递给父类StatelessWidget
的构造函数。
初始化列表 是 Dart 中的一种语法,允许在构造函数执行前初始化类的字段。super(key: key)
表示调用父类的构造函数,并将 key
参数传递给它。这是 Flutter 中 StatelessWidget
和 StatefulWidget
构造函数的常见模式。
-
key
主要用于确保在 widget 树更新时,Flutter 能正确地识别和管理 widget。通常,我们会使用key
来避免某些 widget 状态的丢失,尤其是在有动态更新的情况下。
3. build
方法
@override Widget build(BuildContext context) { // TODO: implement build return Text("000"); }
-
build
方法:在StatelessWidget
中,build
方法是必需的。它是用来描述 UI 结构的函数,每当Widget
需要重新构建时,Flutter 会调用此方法。-
build
方法的参数BuildContext context
是当前 widget 在 widget 树中的位置。 -
在这个例子中,
build
方法返回一个简单的Text
widget,显示字符串"000"
。这意味着每次Widget1
被构建时,它都会显示Text("000")
。
-
-
TODO: implement build
:这只是一个注释,通常用于表示该部分代码需要实现或完善。在这个例子中,可以忽略,因为实际上build
方法已经有实现了。
build可以嵌套
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; main(){ //runApp把home参数里面的Widget画到屏幕上 runApp(MaterialApp(home: Widget1())); } class Widget1 extends StatelessWidget { const Widget1({super.key}); @override Widget build(BuildContext context) { return Column( children: <Widget>[ Text("000"), Text("111"), Widget2(), ], ); } } class Widget2 extends StatelessWidget { const Widget2({super.key}); @override Widget build(BuildContext context) { //这里Widget2对象把build里面返回的Widget作为Widget使用, // 返回给上一层,所以上一层的row,就变成了 111 spacer 222 return Column( children: [ Text("222"), Widget3() ], ); } } class Widget3 extends StatefulWidget { const Widget3({super.key}); @override State<Widget3> createState() => _Widget3State(); } //build可以嵌套,把return的Widget一层层,向上返回 class _Widget3State extends State<Widget3> { int i = 0; @override Widget build(BuildContext context) { return Column( children: <Widget>[Text("333"),ElevatedButton(onPressed: (){ print("${++i}"); setState(() { }); }, child: Text("$i") ) ] ); } }
1. main()
函数
main(){ //runApp把home参数里面的Widget画到屏幕上 runApp(MaterialApp(home: Widget1())); }
-
作用:程序的入口函数。
runApp()
是 Flutter 应用的启动点,它将给定的Widget
显示在屏幕上。 -
MaterialApp
是一个包含 Material Design 组件的应用框架,home: Widget1()
表示应用的首页是Widget1
。
2. Widget1
类(StatelessWidget
)
class Widget1 extends StatelessWidget { const Widget1({super.key});//是const Widget1({Key? key}):super(key: key);的简写 //定义了构造函数 Widget1,它接受一个可选的 Key? key 参数。 //Key 是 Flutter 中用来标识 widget 的标识符,通常用于在 widget 树重建时区分不同的 widget。 //通过 super(key: key),这个 key 参数会传递给父类 StatelessWidget 的构造函数。 @override Widget build(BuildContext context) { return Column( children: <Widget>[ Text("000"), Text("111"), Widget2(), ], ); } }
-
Widget1
是一个StatelessWidget
,意味着它是不可变的,且没有内部状态。 -
build
方法:每次Widget1
被构建时,都会返回一个包含三部分内容的Column
:-
Text("000")
:一个静态文本组件,显示 "000"。 -
Text("111")
:一个静态文本组件,显示 "111"。 -
Widget2()
:另一个自定义的StatelessWidget
,被嵌套在Widget1
中。
-
Column
是一个垂直排列其子组件的布局容器,children
列表中的部件会从上到下显示。
3. Widget2
类(StatelessWidget
)
class Widget2 extends StatelessWidget { const Widget2({super.key}); @override Widget build(BuildContext context) { return Column( children: [ Text("222"), Widget3() ], ); } }
-
Widget2
是另一个StatelessWidget
,其build
方法返回一个包含两部分内容的Column
:-
Text("222")
:显示 "222" 的静态文本组件。 -
Widget3()
:这个部件是嵌套在Widget2
中的,并且它是一个StatefulWidget
,即包含可变状态的 widget。
-
Widget2
和 Widget1
类似,也是一个由垂直布局 Column
组成的容器,内部有文本和另一个部件 Widget3
。
-
build
方法的嵌套:Widget2
返回的是一个Column
,其中包含Text("222")
和Widget3()
。这里的Widget3()
实际上是嵌套了一个StatefulWidget
,并在Widget2
中使用它。 -
层次结构:
Widget1
包含Widget2
,而Widget2
又包含Widget3
,这展示了如何在 Flutter 中进行组件的层次嵌套。
4. Widget3
类(StatefulWidget
)
class Widget3 extends StatefulWidget { const Widget3({super.key}); @override State<Widget3> createState() => _Widget3State(); }
-
Widget3
是一个StatefulWidget
,意味着它包含可变的状态,通常是用来表示UI会变化的情况。 -
StatefulWidget
需要创建与其相关联的状态类,这里是_Widget3State
,它继承自State<Widget3>
。
5. _Widget3State
类(State
)
class _Widget3State extends State<Widget3> { int i = 0; @override Widget build(BuildContext context) { return Column( children: <Widget>[ Text("333"), ElevatedButton( onPressed: (){ print("${++i}"); setState(() {}); }, child: Text("$i") ) ] ); } }
-
_Widget3State
类是Widget3
的状态类,负责管理Widget3
的可变状态。 -
int i = 0;
:定义了一个整数i
,这个变量将用于计数,每次按钮被按下时增加。 -
build
方法:返回一个包含两部分内容的Column
:-
Text("333")
:显示文本 "333"。 -
ElevatedButton
:这是一个按钮,当用户点击按钮时,i
会递增(++i
),并且调用setState()
来通知 Flutter 重新构建该部件,从而更新按钮上显示的数字。
-
setState()
:
-
setState()
用于通知 Flutter 这个部件的状态已经发生变化,从而重新构建build
方法,刷新 UI。在这个例子中,点击按钮会触发setState()
,使得按钮上的文本(显示的数字)发生变化。
6. build
的嵌套
-
嵌套原理:
-
Widget1
中包含了Widget2
,而Widget2
又包含了Widget3
。每一层的build
方法都返回一个 widget,这些 widget 在上层作为子部件使用。 -
Widget2
的build
方法返回了一个Column
,其中包括Text("222")
和Widget3
,从而使得Widget3
成为Widget2
的一部分。 -
Widget1
通过Widget2
进一步嵌套了Widget3
。
-
-
build
方法是构建 Flutter UI 的核心方法,它可以嵌套多个部件。 -
在 Flutter 中,
StatelessWidget
和StatefulWidget
可以嵌套使用,StatelessWidget
通常用于没有可变状态的部件,而StatefulWidget
用于需要管理和更新状态的部件。 -
setState()
是在StatefulWidget
中触发 UI 更新的关键方法,通常在状态发生变化时调用它来更新部件的显示。
通过这种嵌套的方式,Flutter 允许非常灵活的 UI 设计,部件可以被层层嵌套,每一层都可以是独立的 UI 组件,同时也能在某一层管理自己的状态。