trend_tab.dart 4.09 KB
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;
  }
}