Widget,Element 和 RenderObject 类型
虽然Widget是开发人员创建和管理的,但Flutter框架会并行构建和管理另外两棵树,称为元素树和渲染对象树。这三种树用于构建用户画面(UI)并决定何时刷新他们。
StatelessWidget这种widget不需要可变状态。最适合用于描述UI中永不可改的部分。
StatefulWidget这种widget具有可变状态,一般在开发者需要控制widget的生命周期或动态内容时使用。StatefulWidget本身是不可变的,但它的状态是可变的,并且由一个单独的State
一个小计数器案例(结构很简单,小伙伴们可以根据个人的习惯来创建文件目录)。
在lib目录下创建一个counter目录,在该目录下创建一个counter_app_body文件。
void main() {
runApp(const EnhancedCounterApp());
}
class EnhancedCounterApp extends StatelessWidget {
const EnhancedCounterApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: CounterAppBody(),
);
}
}
在counter_app_body创建一个有状态的Widget.
然后在counter目录下在添加一个widget目录,并在该目录下创建app_title文件来显示程序的标题.
class AppTitle extends StatelessWidget {
const AppTitle({super.key});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(120),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.remove,
color: Colors.redAccent,
),
Text(
'计数器App',
style: TextStyle(
color: Colors.black,
fontSize: 20,
),
),
Icon(
Icons.add,
color: Colors.lightGreen,
)
],
),
);
}
}
在widget目录下创建history_widget文件,它用来显示计数器下方的滚动列表。这样做可以提高可读性和UI部分的分离。
在有状态Widget需要初始化或是需要更新时需要使用State类下的一些方法来控制。本程序中使用到了didUpdateWidget来更新添加计数时更新列表的状态。
当我们点击+时才会更新列表,当点击-时,只减少计数器的值,列表不变。
import 'package:flutter/material.dart';
class HistoryWidget extends StatefulWidget {
//计数器历史
final List increasesHistory;
const HistoryWidget({super.key, required this.increasesHistory});
@override
State createState() => _HistoryWidgetState();
}
class _HistoryWidgetState extends State {
//滚动视图控制器
final controller = ScrollController();
//缓存列表
late ListView list = buildList();
//构建列表
ListView buildList() {
return ListView.separated(
key: const Key('历史列表'),
controller: controller,
scrollDirection: Axis.horizontal,
itemCount: widget.increasesHistory.length,
itemBuilder: (_, index) {
return Card(
elevation: 4,
shadowColor: Colors.blueAccent,
child: SizedBox(
width: 40,
height: 40,
child: Center(
child: Text('${widget.increasesHistory[index]}'),
),
),
);
},
separatorBuilder: (_, __) => const SizedBox(width: 10),
);
}
@override
void didUpdateWidget(covariant HistoryWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.increasesHistory.length != oldWidget.increasesHistory.length) {
// 更新列表
list = buildList();
// 移动到尾部
controller.animateTo(
controller.position.maxScrollExtent + 50 + 10,
duration: const Duration(milliseconds: 400),
curve: Curves.ease,
);
}
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
// 标题
const Text(
'计数器列表',
style: TextStyle(
fontSize: 20,
),
),
// 实际的列表
Flexible(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 40,
vertical: 15,
),
child: SizedBox(
height: 40,
child: list,
),
),
),
],
);
}
}
下面来到counter_app_body文件,完成CounterAppBody有状态类的代码
我们需要在State类中添加计数器变量、列表历史和增加和减少计数器的方法
import 'package:counter_app/counter/widgets/app_title.dart';
import 'package:counter_app/counter/widgets/history_widget.dart';
import 'package:flutter/material.dart';
class CounterAppBody extends StatefulWidget {
const CounterAppBody({super.key});
@override
State createState() => _CounterAppBodyState();
}
class _CounterAppBodyState extends State {
//计数器变量
int count = 0;
// 跟踪当按下 '+1' 时计数器状态的变化
List incrementHistory = [];
//将计数器增加1
void increment() {
setState(() {
count++;
incrementHistory = List.from(incrementHistory)..add(count);
});
}
//将计数器减少1
void decrement() {
setState(() {
count--;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const AppTitle(),
//添加两个按钮和计数器文本
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blueAccent,
),
onPressed: decrement,
child: const Text(
'-',
style: TextStyle(fontSize: 30),
),
),
const SizedBox(width: 16),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blueAccent,
),
onPressed: increment,
child: const Text('+', style: TextStyle(fontSize: 30)),
),
],
),
HistoryWidget(
increasesHistory: incrementHistory,
),
],
),
),
);
}
}