You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Windows:将Tab功能集成到AppBar操作区并优化空容器问题

Flutter Windows AppBar 设置按钮Tab切换实现方案

针对你的需求,以下是两种可行的实现方案:


方案一:将设置作为类Tab按钮整合到窗口控制区

把设置按钮放在AppBar右侧的最小化、关闭按钮旁,实现和Tab一致的选中交互,同时移除TabBar中的空容器:

修改后的完整代码

import 'widgets/custom_appbar.dart';
import 'package:flutter/material.dart';
import 'package:window_manager/window_manager.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'constants.dart';
import 'widgets/main_tab/connect_to_server.dart';
import 'widgets/main_tab/create_server.dart';

class CoopAndreasLauncher extends StatefulWidget {
  const CoopAndreasLauncher({super.key});

  @override
  State<CoopAndreasLauncher> createState() => _CoopAndreasLauncherState();
}

class _CoopAndreasLauncherState extends State<CoopAndreasLauncher> with TickerProviderStateMixin {
  final TextEditingController nicknameController = TextEditingController();
  final TextEditingController ipPortController = TextEditingController();
  int maxPlayers = 2;
  String selectedLanguage = 'English';

  late TabController _tabController;
  bool _isSettingsPageActive = false; // 标记是否处于设置页面

  @override
  void initState() {
    super.initState();
    _tabController = TabController(initialIndex: 0, vsync: this, length: 3);
    // 监听Tab切换,更新设置按钮选中状态
    _tabController.addListener(() {
      setState(() {
        _isSettingsPageActive = _tabController.index == 2;
      });
    });
  }

  @override
  void dispose() {
    nicknameController.dispose();
    ipPortController.dispose();
    _tabController.dispose();
    super.dispose();
  }

  late final List<Widget> _actions = [
    // 改造设置按钮为类Tab样式
    IconButton(
      icon: const Icon(FontAwesomeIcons.gear),
      iconSize: 20.0,
      color: _isSettingsPageActive ? Colors.white : Colors.grey[400],
      onPressed: () {
        _tabController.animateTo(2);
      },
    ),
    IconButton(
      icon: const Icon(Icons.minimize),
      iconSize: 20.0,
      onPressed: () {
        windowManager.minimize();
      },
    ),
    IconButton(
      icon: const Icon(Icons.close),
      iconSize: 20.0,
      onPressed: () {
        windowManager.close();
      },
    )
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: CustomAppBar(
        actions: _actions,
        title: TabBar(
          labelColor: Colors.white,
          controller: _tabController,
          indicatorColor: Colors.transparent,
          dividerColor: Colors.transparent,
          splashBorderRadius: const BorderRadius.all(Radius.circular(10.0)),
          tabAlignment: TabAlignment.center,
          // 移除空容器,只保留功能Tab
          tabs: const [
            Tab(
                icon: Icon(FontAwesomeIcons.plug, size: 21.0),
                child: Text(
                    "Connect",
                    style: tabTextStyle,
                )
            ),
            Tab(
                icon: Icon(FontAwesomeIcons.server, size: 21.0),
                child: Text(
                  "Server",
                  style: tabTextStyle,
                )
            ),
          ]
        )
      ),
      body: TabBarView(
        controller: _tabController,
        children: [
          ConnectToServerTab(nicknameController: nicknameController, ipPortController: ipPortController),
          CreateServerTab(nicknameController: nicknameController, ipPortController: ipPortController, maxPlayers: maxPlayers, onMaxPlayersChanged: (value) {
            setState(() {
              maxPlayers = value;
            });
          }),
          // 替换为你的设置页面组件
          const Center(child: Text("设置页面")),
        ]
      ),
    );
  }
}

关键修改点

  1. 添加_isSettingsPageActive变量标记设置页面状态,监听TabController切换事件更新该状态
  2. 给设置按钮添加选中态颜色,和Tab的选中色保持一致
  3. 移除TabBar中的空容器,只保留功能Tab
  4. 保留TabController长度为3,确保TabBarView能正确切换到设置页面

方案二:保留操作区设置按钮,实现完整Tab式交互

如果希望设置按钮的交互完全和Tab对齐(比如点击水波纹效果、选中态高亮),可以将设置按钮包装成Tab样式组件:

核心修改代码片段

// 自定义Tab式设置按钮
Widget _buildSettingsTabButton() {
  return InkWell(
    borderRadius: const BorderRadius.all(Radius.circular(10.0)),
    onTap: () => _tabController.animateTo(2),
    child: Padding(
      padding: const EdgeInsets.symmetric(horizontal: 16),
      child: Icon(
        FontAwesomeIcons.gear,
        size: 20.0,
        color: _isSettingsPageActive ? Colors.white : Colors.grey[400],
      ),
    ),
  );
}

// 更新_actions列表
late final List<Widget> _actions = [
  _buildSettingsTabButton(),
  IconButton(
    icon: const Icon(Icons.minimize),
    iconSize: 20.0,
    onPressed: () => windowManager.minimize(),
  ),
  IconButton(
    icon: const Icon(Icons.close),
    iconSize: 20.0,
    onPressed: () => windowManager.close(),
  )
];

关键修改点

  1. 使用InkWell模拟Tab的点击水波纹效果,和原Tab的splashBorderRadius保持一致
  2. 沿用方案一的选中态逻辑,确保视觉一致性
  3. 交互体验和原生Tab完全对齐,同时保留在窗口控制区的布局

内容的提问来源于stack exchange,提问作者PressF

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 03:04:53