颤动选项卡是否可以具有不同的宽度并将剩余空间均匀分布为左右填充?

mor*_*red 3 dart flutter

这是我尝试这样做的方式,但我显然需要以某种方式计算填充。我正在考虑在最坏的情况下创建某种计算所有这些的函数,但是我可以选择元素并获取值吗?

这大致是我希望它们的样子(之间的空间应根据屏幕尺寸而变化)https://i.imgur.com/huhC9vn.png

我也在想,也许有些屏幕可能无法适应它,因为模拟的屏幕非常大,在这种情况下,我也在考虑设置最小填充尺寸并使其可滚动。

bottom: TabBar(
  labelPadding: EdgeInsets.only(left: 8, right: 8),
  isScrollable: true,
  tabs: <Widget>[
    Tab(
      text: 'General',
    ),
    Tab(
      text: 'Financial',
    ),
    Tab(
      text: 'Experts & Participants',
    ),
  ],
)),
Run Code Online (Sandbox Code Playgroud)

Pab*_*era 7

实现的方式TabBar不允许设置灵活的选项卡。所以你必须计算每个选项卡的水平填充。

您需要获取标签宽度,因此您可以执行以下操作:

  • 将 a 设置GlobalKey为 eachTab然后访问 key.currentContext.size.width
  • 由于key.currentContextnull构建过程中,你需要等待,直到TabBar被渲染,然后得到的标签宽度。为此,您可以使用WidgetsBinding.instance.addPostFrameCallback() inside initState
  • 如果设备方向可以改变,您需要再次计算填充,因此您可以在内部didChangeDependencies而不是 initState.
  • 计算填充后,您需要将该填充存储在变量中并调用setState以更新选项卡的填充。
  • 为避免调用setState整个树,您可以将 放入 TabBar自定义StatefulWidget.
  • 为了能够使用TabBar应用程序中的任何内容执行此操作,您可以创建一个自定义TabBar小部件,该小部件接收TabBar并返回一个带有计算填充的新小部件。

因此,根据您的情况,您可以实施部分或全部提到的要点。这是一个包含所有提到的要点的示例:

class TabBarWithFlexibleTabs extends StatefulWidget implements PreferredSizeWidget {
  TabBarWithFlexibleTabs({this.child});

  final TabBar child;

  @override
  Size get preferredSize => child.preferredSize;

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

class _TabBarWithFlexibleTabsState extends State<TabBarWithFlexibleTabs> {
  final _tabs = <Widget>[];
  final _tabsKeys = <Tab, GlobalKey>{};
  var _tabsPadding = 0.0;

  void _updateTabBarPadding() => setState(() {
        final screenWidth = MediaQuery.of(context).size.width;
        final tabBarWidth = _tabsKeys.values
            .fold(0, (prev, tab) => prev + tab.currentContext.size.width);
        _tabsPadding = tabBarWidth < screenWidth
            ? ((screenWidth - tabBarWidth) / widget.child.tabs.length) / 2
            : widget.child.labelPadding?.horizontal ?? 16.0;
      });

  @override
  void initState() {
    super.initState();
    widget.child.tabs.forEach((tab) => _tabsKeys[tab] = GlobalKey());
    _tabs.addAll(widget.child.tabs
        .map((tab) => Container(key: _tabsKeys[tab], child: tab)));
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    WidgetsBinding.instance.addPostFrameCallback((_) => _updateTabBarPadding());
  }

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: widget.child.tabs.length,
      child: TabBar(
        tabs: _tabs,
        isScrollable: true,
        labelPadding: EdgeInsets.symmetric(
          horizontal: _tabsPadding,
          vertical: widget.child.labelPadding?.vertical ?? 0,
        ),
        // TODO: pass other parameters used in the TabBar received, like this:
        controller: widget.child.controller,
        indicatorColor: widget.child.indicatorColor,
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
        bottom: TabBarWithFlexibleTabs(
          child: TabBar(
            tabs: <Widget>[
              Tab(
                text: 'General',
              ),
              Tab(
                text: 'Financial',
              ),
              Tab(
                text: 'Experts & Participants',
              ),
            ],
          ),
        )
    ),
  );
}
Run Code Online (Sandbox Code Playgroud)

笔记:

  • TabBar如果它不能适应屏幕宽度,它将是可滚动的。
  • 检查// TODO: pass other parameters used in the TabBar received.
  • DefaultTabController如果您想使用自定义的,您可能需要删除。