Files
DMZJ_F/lib/widgets/windows_tab_page.dart
2026-03-07 17:24:59 +08:00

145 lines
4.0 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<WindowsTabItem> tabs;
final int initialIndex;
final Widget? headerAction;
final ValueChanged<int>? onTabChanged;
const WindowsTabPage({
Key? key,
required this.tabs,
this.initialIndex = 0,
this.headerAction,
this.onTabChanged,
}) : super(key: key);
@override
State<WindowsTabPage> createState() => _WindowsTabPageState();
}
class _WindowsTabPageState extends State<WindowsTabPage> {
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,
),
),
),
);
}
}