在Flutter中为BottomNavigationBar添加指示器

3
有没有办法像这张图片一样在BottomNavigatorBarItem中添加指示器? fl

1
你应该考虑使用各种小部件构建自己的BottomNavigationBar UI。等我喝完咖啡后,我会尽量提供完整的代码 xD - OMi Shah
3个回答

1

这个包应该能帮助您实现它。

enter image description here


谢谢。我通过使用BoxDecoration提供activeIcon成功添加了指示器,但是它没有滑动效果。 上面的库提供了滑动效果,但只能显示图标或文本。我克隆并更改了_buildItemWidget函数,使其始终同时显示两者。它非常好用。 - Nguyen Minh Binh

1

你可以使用自定义装饰的 TabBar 替代 BottomNavigationBar

class TopIndicator extends Decoration {
  @override
  BoxPainter createBoxPainter([VoidCallback? onChanged]) {
    return _TopIndicatorBox();
  }
}

class _TopIndicatorBox extends BoxPainter {
  @override
  void paint(Canvas canvas, Offset offset, ImageConfiguration cfg) {
    Paint _paint = Paint()
      ..color = Colors.lightblue
      ..strokeWidth = 5
      ..isAntiAlias = true;

    canvas.drawLine(offset, Offset(cfg.size!.width + offset.dx, 0), _paint);
  }
}

然后使用TapBar(indicator: TopIndicator ...)将装饰传递给TapBar。

tabbar

如果要将TabBar用作Scaffold.bottomNavigationBar,您很可能需要将其包装在Material中以应用背景颜色:

Scaffold(
  bottomNavigationBar: Material(
    color: Colors.white,
    child: TabBar(
      indicator: TopIndicator(),
      tabs: const <Widget>[
        Tab(icon: Icon(Icons.home_outlined), text: 'Reward'),
        ...
      ],
    ),
  ),
  ...
)

感谢Ara Kurghinyan提供的原始想法。


0

我曾经遇到过同样的问题,而且我找到的所有包似乎都需要原始的 IconData,这使得无法使用小部件功能,例如数字徽章(例如未读聊天消息的数量)。

我想出了自己的小解决方案;首先,我制作了一个小部件来显示实际的指示器:

class TabIndicators extends StatelessWidget {
  final int _numTabs;
  final int _activeIdx;
  final Color _activeColor;
  final Color _inactiveColor;
  final double _padding;
  final double _height;

  const TabIndicators({ 
    required int numTabs, 
    required int activeIdx, 
    required Color activeColor, 
    required double padding,
    required double height,
    Color inactiveColor = const Color(0x00FFFFFF),
    Key? key }) : 
    _numTabs = numTabs, 
    _activeIdx = activeIdx,
    _activeColor = activeColor, 
    _inactiveColor = inactiveColor,
    _padding = padding,
    _height = height,
    super(key: key);

  @override
  Widget build(BuildContext context) {

    final elements = <Widget>[];

    for(var i = 0; i < _numTabs; ++i) {
      elements.add(
        Expanded(child: 
          Padding(
            padding: EdgeInsets.symmetric(horizontal: _padding),
            child: Container(color: i == _activeIdx ? _activeColor : _inactiveColor),
          )
        )
      );
    }

    return 
      SizedBox(
        height: _height,
        child: Row(
          mainAxisSize: MainAxisSize.max,
          children: elements,
    ),
      );
  }
}

可以像这样将其添加到实际的BottomNavigationBar之前:

bottomNavigationBuilder: (context, tabsRouter) {
  return Padding(
    padding: const EdgeInsets.only(top: 4.0),
    child: Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        TabIndicators(
          activeIdx: tabsRouter.activeIndex,
          activeColor: Theme.of(context).primaryColor,
          numTabs: 4,
          padding: 25,
          height: 4,
        ),
        BottomNavigationBar(...

这对我来说完美地运行,但为了使其看起来体面,您需要将BottomNavigationBar的高程设置为零,否则指示器和图标之间仍然会有微弱的水平线。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接