Flutter标签页导航插件built_tab_navigator的使用

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

Flutter标签页导航插件built_tab_navigator的使用

built_tab_navigator 插件用于创建具有导航功能的标签页UI。

此插件旨在与 built_valuebuilt_collection 一起使用,因为某些API属性期望使用 EnumClass 对象。

安装

pubspec.yaml 文件的 dependencies: 部分添加以下行:

dependencies:
  built_tab_navigator: <最新版本>

使用

导入此类

import 'package:built_tab_navigator/built_tab_navigator.dart';

默认标签页

默认标签页

BuiltTabNavigator(
  tabs: {
    ExampleTabs.example1: TabRoutesDefinition(
      initialRoute: Example1Routes.root,
      routes: example1Routes,
      tabTitle: "Example 1",
      tabIcon: Icons.ac_unit,
    ),
    ExampleTabs.example2: TabRoutesDefinition(
      initialRoute: Example2Routes.root,
      routes: example2Routes,
      tabTitle: "Example 2",
      tabIcon: Icons.accessibility_new,
    ),
    ExampleTabs.example3: TabRoutesDefinition(
      initialRoute: Example2Routes.root,
      routes: example3Routes,
      tabTitle: "Example 3",
      tabIcon: Icons.adb,
    ),
  },
)

尝试自定义构建器

尝试自定义构建器

BuiltTabNavigator(
  iconBuilder: (context, tab, definition, selected) {
    return Container(
      padding: EdgeInsets.all(4),
      decoration: BoxDecoration(
        color: Colors.purple,
        borderRadius: BorderRadius.circular(20),
      ),
      child: Icon(definition.tabIcon, color: selected ? Colors.white : Colors.black,),
    );
  },
  titleBuilder: (context, tab, definition, selected) {
    return Text(definition.tabTitle, style: TextStyle(fontSize: 20, color: selected ? Colors.purple : Colors.grey),);
  },
  tabs: {
    ExampleTabs.example1: TabRoutesDefinition(
      initialRoute: Example1Routes.root,
      routes: example1Routes,
      tabTitle: "Example 1",
      tabIcon: Icons.ac_unit,
    ),
    ExampleTabs.example2: TabRoutesDefinition(
      initialRoute: Example2Routes.root,
      routes: example2Routes,
      tabTitle: "Example 2",
      tabIcon: Icons.accessibility_new,
    ),
    ExampleTabs.example3: TabRoutesDefinition(
      initialRoute: Example2Routes.root,
      routes: example3Routes,
      tabTitle: "Example 3",
      tabIcon: Icons.adb,
    ),
  },
)

更改布局非常简单

更改布局非常简单

BuiltTabNavigator(
  activeTabColor: Colors.red,
  inactiveTabColor: Colors.white,
  bodyBuilder: (context, tabs, tabView) {
    return Column(
      children: <Widget>[
        Material(
          elevation: 9,
          color: Colors.blue[200],
          child: Container(
            height: 100,
            child: Row(
              children: tabs,
            ),
          ),
        ),
        Expanded(
          child: tabView,
        ),
      ],
    );
  },
  tabs: {
    ExampleTabs.example1: TabRoutesDefinition(
      initialRoute: Example1Routes.root,
      routes: example1Routes,
      tabTitle: "Example 1",
      tabIcon: Icons.ac_unit,
    ),
    ExampleTabs.example2: TabRoutesDefinition(
      initialRoute: Example2Routes.root,
      routes: example2Routes,
      tabTitle: "Example 2",
      tabIcon: Icons.accessibility_new,
    ),
    ExampleTabs.example3: TabRoutesDefinition(
      initialRoute: Example2Routes.root,
      routes: example3Routes,
      tabTitle: "Example 3",
      tabIcon: Icons.adb,
    ),
  },
)

可用的API选项

/// 定义默认的 [selectedTab]
final T activeTab;

/// 定义这个小部件的 [tabs]
/// 每个 [tab] 必须定义一个 [TabRoutesDefinition]
final Map<T, TabRoutesDefinition> tabs;

/// 定义 [bodyBuilder],如果你需要一些非常自定义的东西,比如将标签放在不同的位置(例如顶部),你可以放置 [tabs] 和 [tabView] 在一个自定义布局排列
final BodyBuilder bodyBuilder;

/// 构建每个标签的自定义 [tab] 小部件,请确保调用 [cb] 参数,如果你使用的是可以处理触摸事件的自定义 [GestureDetector | InkWell] 或其他小部件
/// 调用 [cb] 将触发状态构建并按预期更改标签内容
final TabBuilder<T> tabBuilder;

/// 定义 [Color] 用于 [tab] 激活时的 [title] 和 [icon]
final Color activeTabColor;

/// 定义 [Color] 用于 [tab] 未激活时的 [title] 和 [icon]
final Color inactiveTabColor;

/// 定义 [tab] 的点击处理器
final Function(T) tabTap;

/// 构建自定义 [title] 小部件
final TitleBuilder<T> titleBuilder;

/// 构建自定义 [icon] 小部件
final IconBuilder<T> iconBuilder;

/// 每次生成路由时都会被调用,它传递了实际的 [RouteSettings],
/// 拥有该导航器的标签 [T],
/// 用于生成页面的实际路线 [EnumClass],
/// 基于定义的路线的页面构建器 [WidgetBuilder]。
/// 这可以用来返回一个自定义的页面路由包装器,如 `MaterialPageRoute` 或者用自定义动画包装构建器等
final OnGenerateRouteFn<T> onGenerateRoute;

/// 设置 [activetab],如果没有定义,则默认为 [tabs] 中第一个 [tab] 键
final T activeTab;

/// 更改默认标签容器背景
final Color tabContainerBackgroundColor;

/// [didPop] 导航观察器回调
final void Function(T tab, Route route, Route previousRoute) didPop;

/// [didPush] 导航观察器回调
final void Function(T tab, Route route, Route previousRoute) didPush;

/// [didRemove] 导航观察器回调
final void Function(T tab, Route route, Route previousRoute) didRemove;

/// [didReplace] 导航观察器回调
final void Function(T tab, Route newRoute, Route oldRoute) didReplace;

/// 如果 [true],则会实现 [WillPopScope] 小部件用于嵌套导航视图,如果 [false],
/// 后退导航将针对根导航器
/// 默认为 [true]
final bool overridePopBehavior;

/// 设置自定义 [height] 用于标签容器
/// 默认为 [60]
/// 如果定义了 [bodyBuilder],则此属性不会生效
final double tabsHeight;

/// 定义一个自定义构建器来包装每个标签内容的小部件,
/// 这对于构建一个实现自定义动画的小部件很有用
/// 参数:
/// [BuildContext] 当前上下文
/// [EnumClass] 当前正在构建的 `tab`
/// [bool] 当前 `tab` 是否激活
/// [Widget] 实际要包裹的内容,你需要将此小部件作为你小部件实现的子级
final TabContentWrapBuilder contentWrapBuilder;

/// 定义自定义持续时间用于实现的不透明度过渡
/// 如果你实现了自定义 [contentWrapBuilder],则此选项无效果
/// 默认为 [Duration(400ms)]
final Duration contentAnimationDuration;

截图

截图1 截图2 截图3

获取示例代码

你可以查看 示例代码

示例代码

import 'package:built_collection/built_collection.dart';
import 'package:built_tab_navigator/built_tab_navigator.dart';
import 'package:built_value/built_value.dart';
import 'package:flutter/material.dart';

import 'example1_routes.dart';
import 'example2_routes.dart';
import 'example3_routes.dart';

part 'main.g.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

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

  final String title;

  [@override](/user/override)
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: BuiltTabNavigator(
        activeTabColor: Colors.red,
        inactiveTabColor: Colors.white,
        bodyBuilder: (context, tabs, tabView) {
          return Column(
            children: <Widget>[
              Material(
                elevation: 9,
                color: Colors.blue[200],
                child: Container(
                  height: 100,
                  child: Row(
                    children: tabs,
                  ),
                ),
              ),
              Expanded(
                child: tabView,
              ),
            ],
          );
        },
        tabs: {
          ExampleTabs.example1: TabRoutesDefinition(
            initialRoute: Example1Routes.root,
            routes: example1Routes,
            tabTitle: "Example 1",
            tabIcon: Icons.ac_unit,
          ),
          ExampleTabs.example2: TabRoutesDefinition(
            initialRoute: Example2Routes.root,
            routes: example2Routes,
            tabTitle: "Example 2",
            tabIcon: Icons.accessibility_new,
          ),
          ExampleTabs.example3: TabRoutesDefinition(
            initialRoute: Example2Routes.root,
            routes: example3Routes,
            tabTitle: "Example 3",
            tabIcon: Icons.adb,
          ),
        },
      ),
    );
  }
}

class ExampleTabs extends EnumClass {
  static const ExampleTabs example1 = _$example1;
  static const ExampleTabs example2 = _$example2;
  static const ExampleTabs example3 = _$example3;

  const ExampleTabs._(String name) : super(name);

  static BuiltSet<ExampleTabs> get values => _$values;
  static ExampleTabs valueOf(String name) => _$valueOf(name);
}

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

1 回复

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


当然,下面是一个关于如何使用 built_tab_navigator 插件在 Flutter 中实现标签页导航的代码案例。built_tab_navigator 并不是一个官方或广泛认知的 Flutter 插件,但假设它是一个提供标签页导航功能的自定义插件,我们可以模拟一个类似的实现来展示其可能的使用方法。

通常,在 Flutter 中实现标签页导航可以使用 TabBarTabBarView,但为了符合你的要求,我将展示一个假设的 built_tab_navigator 的使用方式。

假设的 built_tab_navigator 使用示例

首先,假设 built_tab_navigator 提供了如下功能:

  • 一个 BuiltTabNavigator 小部件,接受一组标签页和一个初始页面。
  • 每个标签页通过一个配置对象来定义。

以下是一个假设的 built_tab_navigator 使用示例:

import 'package:flutter/material.dart';
import 'package:built_tab_navigator/built_tab_navigator.dart'; // 假设的包路径

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Tab Navigator Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: BuiltTabNavigatorDemo(),
    );
  }
}

class BuiltTabNavigatorDemo extends StatefulWidget {
  @override
  _BuiltTabNavigatorDemoState createState() => _BuiltTabNavigatorDemoState();
}

class _BuiltTabNavigatorDemoState extends State<BuiltTabNavigatorDemo> {
  final List<TabItem> tabItems = [
    TabItem(title: 'Home', icon: Icons.home, page: HomePage()),
    TabItem(title: 'Search', icon: Icons.search, page: SearchPage()),
    TabItem(title: 'Profile', icon: Icons.person, page: ProfilePage()),
  ];

  @override
  Widget build(BuildContext context) {
    // 假设 BuiltTabNavigator 是提供的标签页导航小部件
    return BuiltTabNavigator(
      items: tabItems,
      initialIndex: 0, // 初始选中的标签页索引
      onTabSelected: (index) {
        // 可选的:标签页选中时的回调
        print('Selected tab: $index');
      },
    );
  }
}

// 假设的 TabItem 配置类
class TabItem {
  final String title;
  final IconData icon;
  final Widget page;

  TabItem({required this.title, required this.icon, required this.page});
}

// 假设的 BuiltTabNavigator 小部件实现(模拟)
class BuiltTabNavigator extends StatefulWidget {
  final List<TabItem> items;
  final int initialIndex;
  final ValueChanged<int>? onTabSelected;

  BuiltTabNavigator({
    required this.items,
    required this.initialIndex,
    this.onTabSelected,
  });

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

class _BuiltTabNavigatorState extends State<BuiltTabNavigator> {
  int _selectedIndex = 0;

  @override
  void initState() {
    super.initState();
    _selectedIndex = widget.initialIndex;
  }

  void _onTabTapped(int index) {
    setState(() {
      _selectedIndex = index;
      widget.onTabSelected?.call(index);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Tab Navigator Demo'),
        bottom: TabBar(
          tabs: widget.items.map((item) {
            return Tab(
              icon: Icon(item.icon),
              text: item.title,
            );
          }).toList(),
          currentIndex: _selectedIndex,
          onTabSelected: _onTabTapped,
        ),
      ),
      body: TabBarView(
        children: widget.items.map((item) => item.page).toList(),
        controller: TabController(length: widget.items.length, vsync: Vsyncer(), initialIndex: _selectedIndex),
      ),
    );
  }
}

// 简单的 Vsync 实现,用于 TabController
class Vsyncer implements TickerProvider {
  @override
  Ticker createTicker(TickerCallback onTick) {
    throw UnimplementedError();
  }

  @override
  bool disposeTicker(Ticker ticker) {
    throw UnimplementedError();
  }
}

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

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

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

注意事项

  1. 包导入import 'package:built_tab_navigator/built_tab_navigator.dart'; 是一行假设的代码,实际使用时需要替换为真实的包路径。
  2. TickerProviderVsyncer 类是一个简化的 TickerProvider 实现,用于 TabController。在实际应用中,你可能会使用 SingleTickerProviderStateMixin 或其他合适的 TickerProvider
  3. 自定义实现:上述代码展示了如何使用 TabBarTabBarView 来模拟一个标签页导航器的功能。如果 built_tab_navigator 真实存在,其使用方式可能会有所不同,但基本思想类似。

希望这个示例能帮你理解如何在 Flutter 中实现标签页导航。如果有实际的 built_tab_navigator 插件,请参考其官方文档以获取准确的使用方法。

回到顶部