Flutter标签页管理插件blossom_tabs的使用

发布于 1周前 作者 zlyuanteng 来自 Flutter

Flutter标签页管理插件blossom_tabs的使用

特性

示例图
  • 您可以拖拽并重新排序标签页。
  • 动态地在运行时添加标签页。
  • 保存当前标签页管理器的状态以便下次使用(例如,在应用重启时)。
  • 自定义外观和行为。

开始使用

首先,在您的项目中添加插件:

blossom_tabs: ^4.0.0

然后导入该插件:

import 'package:blossom_tabs/blossom_tabs.dart';

使用方法

您可以在widget树中这样添加:

// 配置`controller`
var _controller = BlossomTabController<int>(tabs: []); // 推断数据类型以方便访问

return BlossomTabControllerScope<int>(
  controller: _controller,
  child: Scaffold(
    appBar: BlossomTabBar<int>(
      height: 48,
      selectedColor: Colors.blue,
      stickyColor: Colors.white,
      backgroundColor: Colors.blue.withOpacity(0.3),
      dividerColor: Colors.blue,
      tabBuilder: (context, tab, isActive) => Text(tab.id), // 显示标签页的ID
    ),
    body: BlossomTabView<int>(
      builder: (tab) => Text(tab.id) // 显示标签页的内容
    ),
  ),
);

示例代码

以下是一个完整的示例代码,展示了如何使用blossom_tabs插件:

import 'dart:convert';
import 'dart:math';

import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:blossom_tabs/blossom_tabs.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
  doWhenWindowReady(() {
    const initialSize = Size(800, 450);
    appWindow.minSize = initialSize;
    appWindow.size = initialSize;
    appWindow.alignment = Alignment.center;
    appWindow.show();
  });
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

Widget buildTab(
  BuildContext context, {
  required bool isActive,
  bool useRow = true,
  Widget? icon,
  Widget? activeIcon,
  String? title,
  TextStyle? style,
  TextStyle? activeStyle,
}) {
  var children = [
    (isActive ? activeIcon ?? icon : icon) ??
        const SizedBox(
          width: 10,
        ),
    if (title != null)
      Flexible(
        child: Text(
          title,
          softWrap: false,
          overflow: TextOverflow.fade,
          style: isActive ? activeStyle ?? style : style,
        ),
      ),
  ];
  return Padding(
    padding: const EdgeInsets.symmetric(horizontal: 4.0),
    child: useRow
        ? Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Row(children: children),
            ],
          )
        : Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: children,
              ),
            ],
          ),
  );
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  var _controller = BlossomTabController<int>(tabs: []);
  var _tabs = <BlossomTab<int>>[];

  BlossomTab<int> _getTab(String e) => BlossomTab<int>(
        id: e,
        data: int.parse(e.codeUnits.join()),
        title: e.toUpperCase(),
        isSticky: e == 'd',
      );

  @override
  void initState() {
    _tabs = ['a', 'b', 'c', 'd', 'e']
        .map(
          (e) => _getTab(e),
        )
        .toList();
    _controller = BlossomTabController<int>(currentTab: 'b', tabs: _tabs);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return BlossomTabControllerScope(
      controller: _controller,
      child: Scaffold(
        appBar: PreferredSize(
          preferredSize: const Size.fromHeight(85),
          child: Stack(
            children: [
              MoveWindow(
                child: BlossomTabBar<int>(
                  height: 85,
                  bottomBarHeight: 40,
                  selectedColor: Colors.blue,
                  dragColor: Colors.blue.withOpacity(0.6),
                  stickyColor: Colors.white,
                  backgroundColor: Colors.blue.withOpacity(0.3),
                  dividerColor: Colors.blue,
                  bottomColor: Colors.blue,
                  margin: const EdgeInsets.only(left: 4, top: 4, right: 140),
                  tabBarMargin: 4,
                  tabBuilder: (context, tab, isActive) => buildTab(
                    context,
                    isActive: isActive,
                    title: tab.id,
                    activeStyle:
                        tab.id == 'd' ? null : const TextStyle(color: Colors.white),
                    icon: tab.id == 'd'
                        ? null
                        : const Padding(
                            padding: EdgeInsets.all(4.0),
                            child: Icon(
                              Icons.ac_unit,
                              size: 14,
                              color: Colors.black26,
                            ),
                          ),
                    activeIcon: tab.id == 'd'
                        ? null
                        : const Padding(
                            padding: EdgeInsets.all(8.0),
                            child: Icon(
                              Icons.ac_unit,
                              size: 14,
                              color: Colors.white,
                            ),
                          ),
                  ),
                  tabActions: (context, tab) => [
                    if (tab.id != 'd')
                      Listener(
                        onPointerDown: (_) {
                          _controller.removeTabById(tab.id);
                        },
                        child: const Padding(
                          padding: EdgeInsets.all(4.0),
                          child: Icon(
                            Icons.close,
                            size: 14,
                            color: Colors.white,
                          ),
                        ),
                      ),
                  ],
                  bottomBar: BlossomTabControllerScopeDescendant<int>(
                      builder: (context, controller) {
                    // Future.delayed(Duration.zero)
                    //     .then((_) => print(jsonEncode(controller.toJson())));
                    return Container(
                      color: controller.currentTab == 'd' ? Colors.white : null,
                    );
                  }),
                  actions: [
                    Padding(
                      padding: const EdgeInsets.only(left: 6.0),
                      child: NewTabBtn(
                        onTap: () {
                          final z = _controller.tabs.map((e) => e.id).toList()..sort();
                          var c = z.isEmpty ? 'a' : z.last;
                          final lastCharacter =
                              String.fromCharCode(c.codeUnitAt(c.length - 1) + 1);
                          c = c.substring(0, c.length - 1) + lastCharacter;
                          _controller.addTab(_getTab(c));
                        },
                      ),
                    )
                  ],
                ),
              ),
              Positioned(
                right: 0,
                child: WindowButtons(),
              ),
            ],
          ),
        ),
        body: Row(
          children: [
            BlossomVerticalTabBar<int>(
              width: 240,
              sideBarWidth: 180,
              selectedColor: Colors.blue,
              dragColor: Colors.blue.withOpacity(0.6),
              stickyColor: Colors.white,
              backgroundColor: Colors.blue.withOpacity(0.3),
              dividerColor: Colors.blue,
              sideBarColor: Colors.blue,
              margin: const EdgeInsets.only(left: 0, top: 0, right: 0, bottom: 40),
              tabBarMargin: 0,
              showIndicator: true,
              indicatorColor: Colors.white,
              tabBuilder: (context, tab, isActive) => buildTab(
                context,
                isActive: isActive,
                useRow: false,
                title: tab.id,
                activeStyle: tab.id == 'd' ? null : const TextStyle(color: Colors.white),
                activeIcon: tab.id == 'd'
                    ? null
                    : const Padding(
                        padding: EdgeInsets.all(8.0),
                        child: Icon(
                          Icons.ac_unit,
                          size: 14,
                          color: Colors.white,
                        ),
                      ),
              ),
              sideBar: BlossomTabControllerScopeDescendant<int>(
                  builder: (context, controller) {
                // Future.delayed(Duration.zero)
                //     .then((_) => print(jsonEncode(controller.toJson())));
                return Container(
                  color: controller.currentTab == 'd' ? Colors.white : null,
                );
              }),
              actions: [
                Padding(
                  padding: const EdgeInsets.only(top: 6.0),
                  child: NewTabBtn(
                    onTap: () {
                      final z = _controller.tabs.map((e) => e.id).toList()..sort();
                      var c = z.isEmpty ? 'a' : z.last;
                      final lastCharacter =
                          String.fromCharCode(c.codeUnitAt(c.length - 1) + 1);
                      c = c.substring(0, c.length - 1) + lastCharacter;
                      _controller.addTab(_getTab(c));
                    },
                  ),
                )
              ],
            ),
            Expanded(
              child: BlossomTabView<int>(
                builder: (tab) => ColorBox(
                  child: Center(child: ColorBox(child: Center(child: Text(tab.id)))),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class NewTabBtn extends StatefulWidget {
  const NewTabBtn({
    Key? key,
    required this.onTap,
  }) : super(key: key);
  final void Function() onTap;

  @override
  State<NewTabBtn> createState() => _NewTabBtnState();
}

class _NewTabBtnState extends State<NewTabBtn> {
  var _opacity = 0.1;
  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: widget.onTap,
      onHover: (h) => setState(() => _opacity = h ? 0.3 : 0.1),
      child: Container(
        padding: const EdgeInsets.all(2.0),
        color: Colors.blue.withOpacity(_opacity),
        child: const Icon(
          Icons.add,
          size: 22,
          color: Colors.white,
        ),
      ),
    );
  }
}

class ColorBox extends StatefulWidget {
  const ColorBox({Key? key, this.child}) : super(key: key);

  final Widget? child;

  @override
  _ColorBoxState createState() => _ColorBoxState();
}

class _ColorBoxState extends State<ColorBox> {
  Color? _color;

  _randomColor() => Color(0xFF000000 + Random().nextInt(0x00FFFFFF));

  @override
  void initState() {
    _color = _randomColor();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        setState(() {
          _color = _randomColor();
        });
      },
      child: Container(width: 150, height: 150, color: _color, child: widget.child),
    );
  }
}

final buttonColors = WindowButtonColors(
  iconNormal: Colors.blue,
  mouseOver: Colors.blue.withOpacity(0.2),
  mouseDown: Colors.blue,
);

final closeButtonColors = WindowButtonColors(
  mouseOver: Colors.red.withOpacity(0.9),
  mouseDown: Colors.red,
  iconNormal: Colors.blue,
);

class WindowButtons extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        MinimizeWindowButton(colors: buttonColors),
        MaximizeWindowButton(colors: buttonColors),
        CloseWindowButton(colors: closeButtonColors),
      ],
    );
  }
}

其他信息

此外,您可以使用BlossomTabControllerScopeDescendant监听标签页状态的变化,例如:

BlossomTabControllerScopeDescendant<int>(
  builder: (context, controller) {
    return Container(
      color: controller.currentTab == 'd' ? Colors.white : Colors.blue,
    );
});

更多关于Flutter标签页管理插件blossom_tabs的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter标签页管理插件blossom_tabs的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用Flutter插件blossom_tabs来管理标签页的示例代码。blossom_tabs是一个用于在Flutter应用中创建和管理标签页的插件。以下示例展示了如何集成和使用这个插件。

首先,确保你已经在pubspec.yaml文件中添加了blossom_tabs依赖:

dependencies:
  flutter:
    sdk: flutter
  blossom_tabs: ^latest_version  # 请替换为最新版本号

然后,运行flutter pub get来安装依赖。

接下来,你可以按照以下步骤在你的Flutter应用中使用blossom_tabs

  1. 导入包

在你的Dart文件中导入blossom_tabs包:

import 'package:blossom_tabs/blossom_tabs.dart';
  1. 定义标签页内容

定义你想要在每个标签页中显示的内容。例如,创建两个简单的页面:

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Text('Home Page'));
  }
}

class SettingsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Text('Settings Page'));
  }
}
  1. 使用BlossomTabs

在你的主应用中使用BlossomTabs来管理这些标签页。例如,在MyApp中:

import 'package:flutter/material.dart';
import 'package:blossom_tabs/blossom_tabs.dart';

// 导入你定义的页面
import 'home_page.dart';
import 'settings_page.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('BlossomTabs Example'),
        ),
        body: BlossomTabs(
          tabs: [
            BlossomTab(
              title: 'Home',
              icon: Icon(Icons.home),
              child: HomePage(),
            ),
            BlossomTab(
              title: 'Settings',
              icon: Icon(Icons.settings),
              child: SettingsPage(),
            ),
          ],
          initialIndex: 0, // 初始选中的标签页索引
          onTabChanged: (index) {
            // 可选:标签页切换时的回调
            print('Selected tab index: $index');
          },
        ),
      ),
    );
  }
}

在这个示例中:

  • BlossomTabs组件用于管理多个标签页。
  • BlossomTab对象定义了每个标签页的标题、图标和内容。
  • initialIndex参数指定了初始选中的标签页索引。
  • onTabChanged是一个可选的回调,当标签页切换时会触发。
  1. 运行应用

现在,你可以运行你的Flutter应用,应该会看到一个包含两个标签页的界面,点击不同的标签可以切换显示的内容。

这个示例展示了如何使用blossom_tabs插件来创建和管理标签页。根据实际需求,你可以进一步自定义标签页的外观和行为。

回到顶部