trend_tab.dart
4.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../controllers/trend/trend_controller.dart';
import '../../widgets/trend/trend_type_tab_bar.dart';
import '../../widgets/trend/hrv_trend_view.dart';
import '../../widgets/trend/activity_trend_view.dart';
import '../../widgets/trend/sleep_trend_view.dart';
/// 趋势大 Tab 页面主视图
/// 采用 StatefulWidget 绑定 SingleTickerProviderStateMixin 并通过 TabController
/// 控制 TabBar 与 TabBarView 的同步滑动,实现极具高级感的跟手划动效果。
class TrendTab extends StatefulWidget {
const TrendTab({super.key});
@override
State<TrendTab> createState() => _TrendTabState();
}
class _TrendTabState extends State<TrendTab> with SingleTickerProviderStateMixin {
late final TabController _tabController;
late final TrendController _trendController;
late final Worker _rxWorker;
static const _bgColor = Color(0xFFF5F2FF);
static const _h1 = Color(0xFF0F0F11);
// 三个内容区(包裹 KeepAliveWrapper 以记忆滑动/图表状态,确保子 View 能继续保持纯净的 GetView 规范)
static const _contentViews = [
KeepAliveWrapper(child: HrvTrendView()),
KeepAliveWrapper(child: ActivityTrendView()),
KeepAliveWrapper(child: SleepTrendView()),
];
@override
void initState() {
super.initState();
_trendController = Get.find<TrendController>();
// 初始化 TabController
_tabController = TabController(
length: 3,
vsync: this,
initialIndex: _trendController.selectedTypeIndex.value,
);
// 1. 当滑动/点击切换页面时,同步更新 TrendController 状态
_tabController.addListener(() {
if (!_tabController.indexIsChanging) {
_trendController.changeType(_tabController.index);
}
});
// 2. 当外部修改 selectedTypeIndex 时,同步动画跳转 TabBarView
_rxWorker = ever(_trendController.selectedTypeIndex, (index) {
if (_tabController.index != index) {
_tabController.animateTo(index);
}
});
}
@override
void dispose() {
_rxWorker.dispose();
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final topPadding = MediaQuery.of(context).padding.top;
return Container(
color: _bgColor,
child: Column(
children: [
// ── 状态栏占位 + 标题栏 ──
Container(
color: _bgColor,
padding: EdgeInsets.only(top: topPadding),
child: _buildAppBar(),
),
// ── 第1层:原生 TabBar(支持跟手滑动指示器) ──
Container(
color: _bgColor,
child: TrendTypeTabBar(tabController: _tabController),
),
// ── 内容区:TabBarView 提供极其平滑、跟手的原生翻页动画 ──
Expanded(
child: TabBarView(
controller: _tabController,
children: _contentViews,
),
),
],
),
);
}
Widget _buildAppBar() {
return SizedBox(
height: 48,
child: const Padding(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
child: Row(
children: [
Text(
'趋势',
style: TextStyle(
color: _h1,
fontSize: 24,
fontWeight: FontWeight.w600,
),
),
],
),
),
);
}
}
/// 专用于在 TabBarView/PageView 中保持子组件状态的轻量级包装器
/// 使得子 View 可以维持无状态的 GetView 极简设计规范
class KeepAliveWrapper extends StatefulWidget {
final Widget child;
const KeepAliveWrapper({super.key, required this.child});
@override
State<KeepAliveWrapper> createState() => _KeepAliveWrapperState();
}
class _KeepAliveWrapperState extends State<KeepAliveWrapper>
with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context);
return widget.child;
}
}