import 'package:fluent_ui/fluent_ui.dart' as fluent; import 'package:flutter/material.dart'; /// Windows平台专用的标签页容器,使用Fluent UI的TabView样式 /// 替代移动端的Scaffold + TabAppBar + TabBarView组合 class WindowsTabPage extends StatefulWidget { final List tabs; final int initialIndex; final Widget? headerAction; final ValueChanged? onTabChanged; const WindowsTabPage({ Key? key, required this.tabs, this.initialIndex = 0, this.headerAction, this.onTabChanged, }) : super(key: key); @override State createState() => _WindowsTabPageState(); } class _WindowsTabPageState extends State { late int _currentIndex; @override void initState() { super.initState(); _currentIndex = widget.initialIndex; } @override Widget build(BuildContext context) { // 使用maybeOf避免没有FluentTheme祖先时抛出异常 final fluentTheme = fluent.FluentTheme.maybeOf(context) ?? fluent.FluentThemeData(); final materialTheme = Theme.of(context); final isDark = materialTheme.brightness == Brightness.dark; final tabBarBg = isDark ? const Color(0xff202020) : const Color(0xfff0f0f0); return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Fluent 样式标签栏 Container( color: tabBarBg, child: Row( children: [ Expanded( child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: List.generate(widget.tabs.length, (i) { final selected = i == _currentIndex; return _TabButton( label: widget.tabs[i].label, selected: selected, onTap: () { setState(() => _currentIndex = i); widget.onTabChanged?.call(i); }, ); }), ), ), ), if (widget.headerAction != null) Padding( padding: const EdgeInsets.symmetric(horizontal: 4), child: widget.headerAction!, ), ], ), ), // 分隔线 Divider( height: 1, thickness: 1, color: materialTheme.dividerColor, ), // 内容区 Expanded( child: IndexedStack( index: _currentIndex, children: widget.tabs.map((t) => t.body).toList(), ), ), ], ); } } class WindowsTabItem { final String label; final Widget body; const WindowsTabItem({required this.label, required this.body}); } /// 单个标签按钮,Fluent Pivot样式 class _TabButton extends StatelessWidget { final String label; final bool selected; final VoidCallback onTap; const _TabButton({ required this.label, required this.selected, required this.onTap, }); @override Widget build(BuildContext context) { final fluentTheme = fluent.FluentTheme.maybeOf(context) ?? fluent.FluentThemeData(); final accent = fluentTheme.accentColor; final textColor = selected ? accent : fluentTheme.resources.textFillColorSecondary; return GestureDetector( onTap: onTap, behavior: HitTestBehavior.opaque, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( border: Border( bottom: BorderSide( color: selected ? accent : Colors.transparent, width: 2, ), ), ), child: Text( label, style: TextStyle( fontSize: selected ? 18 : 15, fontWeight: selected ? FontWeight.bold : FontWeight.normal, color: textColor, ), ), ), ); } }