前一阶段,我们学习的一直是StatelessWidget,无状态组件,从字面意义上看,是相对简单的组件,因为没有状态的变化,初始化后就“死了”,不会再有变动。
本文要学习StatefulWidget,顾名思义,是有状态的组件,状态的变化会改变Widget的显示,Let us learn it!
学习笔记
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(primarySwatch: Colors.blue),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _number = 0;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("flutter demo"),
),
body: Column(
children: [
Text(
"$_number",
style: Theme.of(context).textTheme.headline1,
),
ElevatedButton(
onPressed: () {
setState(() {
_number++;
});
},
child: Text("增加"))
],
),
);
}
}
重点看
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
_MyHomePageState createState() => _MyHomePageState();
}
StatefulWidget是一个抽象类,想继承它,必须重写它的抽象方法
abstract class StatefulWidget extends Widget {
/// Initializes [key] for subclasses.
const StatefulWidget({ Key? key }) : super(key: key);
/// Creates a [StatefulElement] to manage this widget's location in the tree.
///
/// It is uncommon for subclasses to override this method.
StatefulElement createElement() => StatefulElement(this);
/// Creates the mutable state for this widget at a given location in the tree.
///
/// Subclasses should override this method to return a newly created
/// instance of their associated [State] subclass:
///
/// ```dart
/// @override
/// _MyState createState() => _MyState();
/// ```
///
/// The framework can call this method multiple times over the lifetime of
/// a [StatefulWidget]. For example, if the widget is inserted into the tree
/// in multiple locations, the framework will create a separate [State] object
/// for each location. Similarly, if the widget is removed from the tree and
/// later inserted into the tree again, the framework will call [createState]
/// again to create a fresh [State] object, simplifying the lifecycle of
/// [State] objects.
State createState(); // ignore: no_logic_in_create_state, this is the original sin
}
抽象方法就是State createState(); 没有方法体,需要子类去自己实现。
这个方法名是创建状态,返回值也是状态。
那我们是如何实现的呢,看下面👇
_MyHomePageState createState() => _MyHomePageState();
相当我们会创建一个_MyHomePageState状态
_MyHomePageState()就是调用了class _MyHomePageState默认的构造方法。
也就是说,我们重写的createState(),就是调用State的构造方法。
createState(创建状态) => State构造😁
_MyHomePageState 是继承自 State 的
State也是个抽象类,需要重写build方法
build方法返回的是一个widget,在widget里写我们想要的布局
class _MyHomePageState extends State<MyHomePage> {
int _number = 0;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("flutter demo"),
),
body: Column(
children: [
Text(
"$_number",
style: Theme.of(context).textTheme.headline1,
),
ElevatedButton(
onPressed: () {
setState(() {
_number++;
});
},
child: Text("增加"))
],
),
);
}
}
显示效果
注意按钮中的点击事件:
onPressed: () {
setState(() {
_number++;
});
},
是在点击事件内部又调用了setState(),
setState()内部设置了数字自增的逻辑
不调用setState()是没有效果的。
每点击一次setState(),
都会调用一次整个State的build方法
当build内部的子Widget用const 修饰,就不会被重新创建,有利于性能优化
2.给ListView动态添加Item
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(primarySwatch: Colors.blue),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> _list = [];
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("flutter demo"),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
setState(() {
_list.add("新增一条消息");
});
},
),
body: Center(
child: ListView(
children: _list.map((value) {
return ListTile(
title: Text(value),
);
}).toList(),
),
));
}
}
看效果
分析
还是使用StatefulWidget实现
重点看状态类
class _MyHomePageState extends State<MyHomePage> {
List<String> _list = [];
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("flutter demo"),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
setState(() {
_list.add("新增一条消息");
});
},
),
body: Center(
child: ListView(
children: _list.map((value) {
return ListTile(
title: Text(value),
);
}).toList(),
),
));
}
}
设置了一个悬浮按钮FloatingActionButton
在按钮的点击事件内,会给字符串列表_list添加一条内容 _list.add(“新增一条消息”);
当执行完setState后,会重新执行build,此时_list内容已经被修改过了
所以可以创建新的列表。
3.关键字const和final的区别
const代表常量,常量要在程序运行前就被赋值好,并且程序运行后也不可以修改,常量必须是静态的。(声明就要赋值)
final代表不可修改,final是运行时常量,可以运行时再赋值,只能赋值一次。(可以先声明,再赋值)
final修饰List<> 是可以给List增添元素的。