一个案例
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'KeepAlive Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
// DefaultTabController: 提供了一个 Tab 管理器,负责记录当前选中的 Tab
// length: 2 表示总共有两个 Tab。
return DefaultTabController(
length: 2, // 两个标签页
child: Scaffold(
appBar: AppBar(
title: const Text("AutomaticKeepAliveClientMixin 示例"),
// bottom: TabBar(...) 表示在底部嵌一个 TabBar(标签页按钮)。
bottom: const TabBar(
tabs: [
Tab(text: "没有 KeepAlive"),
Tab(text: "有 KeepAlive"),
],
),
),
// TabBarView 是 Tab 对应的内容区域。
body: const TabBarView(children: [NoKeepAlivePage(), KeepAlivePage()]),
),
);
}
}
class NoKeepAlivePage extends StatefulWidget {
const NoKeepAlivePage({super.key});
@override
State<NoKeepAlivePage> createState() => _NoKeepAlivePageState();
}
class _NoKeepAlivePageState extends State<NoKeepAlivePage> {
int counter = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text("Counter: $counter", style: const TextStyle(fontSize: 24)),
),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => counter++),
child: const Icon(Icons.add),
),
);
}
}
class KeepAlivePage extends StatefulWidget {
const KeepAlivePage({super.key});
@override
State<KeepAlivePage> createState() => _KeepAlivePageState();
}
class _KeepAlivePageState extends State<KeepAlivePage>
with AutomaticKeepAliveClientMixin {
int counter = 0;
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
body: Center(
child: Text("Counter: $counter", style: const TextStyle(fontSize: 24)),
),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => counter++),
child: const Icon(Icons.add),
),
);
}
}

DefaultTabController是什么
它是 Flutter 提供的一个封装类,用来管理 TabBar(标签栏) 和 TabBarView(标签页内容) 之间的联动。
它内部创建了一个 TabController
,并通过 InheritedWidget
向子树提供。
也就是说:
- 你不用自己手动写
TabController controller = TabController(length: x, vsync: this);
DefaultTabController
自动帮你完成。- 子组件(
TabBar
、TabBarView
)会通过DefaultTabController.of(context)
拿到同一个TabController
,从而实现同步。
常用构造函数:
DefaultTabController({
Key? key,
required int length, // 必须:tab 页数量
int initialIndex = 0, // 初始显示第几个 tab
required Widget child, // 子树,通常包含 TabBar + TabBarView
})
DefaultTabController内部如何创建TabController
class DefaultTabController extends StatefulWidget {
// 构造函数阶段:只是接收参数(length、initialIndex、child)。
// 里面并没有 TabController。
const DefaultTabController({
super.key,
required this.length,
this.initialIndex = 0,
required this.child,
this.animationDuration,
}) : assert(length >= 0),
assert(length == 0 || (initialIndex >= 0 && initialIndex < length));
final int length;
final int initialIndex;
final Widget child;
final Duration? animationDuration;
static TabController? of(BuildContext context) {
final _DefaultTabControllerScope? scope =
context.dependOnInheritedWidgetOfExactType<_DefaultTabControllerScope>();
return scope?._controller;
}
@override
_DefaultTabControllerState createState() => _DefaultTabControllerState();
}
class _DefaultTabControllerState extends State<DefaultTabController> {
TabController? _controller;
// State 初始化时(initState):
// 内部真正 new 了一个 TabController,并保存到 _controller。
@override
void initState() {
super.initState();
// 在初始化方法的时候创建了 TabController,赋值给局部变量
_controller = TabController(
length: widget.length,
vsync: this, // with TickerProviderStateMixin
initialIndex: widget.initialIndex,
animationDuration: widget.animationDuration,
);
}
@override
Widget build(BuildContext context) {
//build 阶段:用 _DefaultTabControllerScope 把 _controller 往子树传。
return _DefaultTabControllerScope(
controller: _controller!,
child: widget.child, // 这个是子树,里面有 TabBar 和 TabBarView
);
}
@override
void dispose() {
_controller?.dispose();
super.dispose();
}
}
class _DefaultTabControllerScope extends InheritedWidget {
const _DefaultTabControllerScope({
required TabController controller,
required Widget child,
}) : _controller = controller, super(child: child);
final TabController _controller;
@override
bool updateShouldNotify(_DefaultTabControllerScope old) {
return _controller != old._controller;
}
}
TabBar
在构建时会用 DefaultTabController.of(context)
找到最近的 TabController
。
TabBarView
内部用的是一个 PageView
(本质是个横向滚动的页面容器)。它在构建时也会获取同一个 TabController
。
然后这两个都会去监听TabController
如果不用 DefaultTabController
class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
late TabController _controller;
@override
void initState() {
super.initState();
_controller = TabController(length: 2, vsync: this);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
bottom: TabBar(controller: _controller, tabs: [...]),
),
body: TabBarView(controller: _controller, children: [...]),
);
}
}