初始化
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 懒加载 + 保活的 IndexedStack(底部 tab 内容页标准写法)
|
||||
///
|
||||
/// 没进过的 tab 用空盒占位,首次切到才真正 build;进过一次就一直留在树里,
|
||||
/// 切走只是不 paint,state / 滚动位置 / 播放器全部保留。
|
||||
/// 相比 PageView:不需要 AutomaticKeepAlive 保活,也不会预建相邻页。
|
||||
///
|
||||
/// 非当前 tab 用 TickerMode(enabled: false) 关掉:IndexedStack 只是不 paint,
|
||||
/// 离屏页的动画/定时器照样在跑(跑马灯、Shimmer、轮播),看不见还空转。
|
||||
class LazyIndexedStack extends StatefulWidget {
|
||||
final int index;
|
||||
final List<Widget> children;
|
||||
|
||||
const LazyIndexedStack({super.key, required this.index, required this.children});
|
||||
|
||||
@override
|
||||
State<LazyIndexedStack> createState() => _LazyIndexedStackState();
|
||||
}
|
||||
|
||||
class _LazyIndexedStackState extends State<LazyIndexedStack> {
|
||||
//已建过的下标:进过一次就永久保活,不再退回占位
|
||||
final _loaded = <int>{};
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loaded.add(widget.index);
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant LazyIndexedStack oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
_loaded.add(widget.index);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IndexedStack(
|
||||
// 必须 expand:默认的 loose 会让子页拿到非 tight 约束,从而不再是 relayout boundary,
|
||||
// 离屏页一脏就把整个 stack 拖着重新布局(PageView 原来给的是 tight,每页各自隔离)。
|
||||
// 顺带保证「根节点自身不撑满」的页也能满屏,不依赖各页自觉
|
||||
sizing: StackFit.expand,
|
||||
index: widget.index,
|
||||
children: List.generate(
|
||||
widget.children.length,
|
||||
(i) => _loaded.contains(i)
|
||||
? TickerMode(enabled: i == widget.index, child: widget.children[i])
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user