Nguyen  Minh Binh
Nguyen Minh Binh

Reputation: 24423

Add indicator to BottomNavigationBar in flutter

any way to add indicator to BottomNavigatorBarItem like this image? fl

Upvotes: 3

Views: 8409

Answers (3)

Wolfgang Schneider
Wolfgang Schneider

Reputation: 1

I've had the same problem and all the packages I found seem to require raw IconData, which makes it impossible to use widget functionality like number badges (e.g. the number of unread chat messages).

I came up with my own little solution; first, I made a widget to display the actual indicators:

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,
    ),
      );
  }
}

This can be prepended to the actual BottomNavigationBar like this:

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(...

This works perfectly well for me, but to make it look decent, you'd have to set the BottomNavigationBar's elevation to zero, otherwise there's still a faint horizontal line between the indicators and the icons.

Upvotes: 0

DurandA
DurandA

Reputation: 1550

You can use a TabBar instead of a BottomNavigationBar using a custom decoration:

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);
  }
}

Then pass the decoration to the TapBar using TapBar(indicator: TopIndicator ...).

tabbar

To use the TabBar as the Scaffold.bottomNavigationBar, you will most likely want to wrap it in a Material to apply a background color:

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

Thanks Ara Kurghinyan for the original idea.

Upvotes: 1

Darshan
Darshan

Reputation: 11669

This package should be able to help you achieve it.

enter image description here

Upvotes: 1

Related Questions