pub pub2

Tabbed view

Flutter widget inspired by the classic Desktop-style tab component. Supports customizable themes.

classiccut darkcut mobilecut minimalistcut fromthescratchcut

Get started

The TabbedViewTheme.classic() method builds the default theme.

    List<TabData> tabs = [];
    for (var i = 1; i < 7; i++) {
      Widget tabContent = Center(child: Text('Content $i'));
      tabs.add(TabData(text: 'Tab $i', content: tabContent));
    }
    TabbedWiew tabbedView = TabbedWiew(controller: TabbedWiewController(tabs));

classic

Content builder

It allows creating the contents of the tab dynamically during the selection event.

    var tabs = [
      TabData(text: 'Tab 1'),
      TabData(text: 'Tab 2'),
      TabData(text: 'Tab 3')
    ];

    TabbedWiew tabbedView = TabbedWiew(
        controller: TabbedWiewController(tabs),
        contentBuilder: (BuildContext context, int tabIndex) {
          int i = tabIndex + 1;
          return Center(child: Text('Content $i'));
        });

Close button tooltip

    var tabs = [
      TabData(text: 'Tab 1'),
      TabData(text: 'Tab 2'),
      TabData(text: 'Tab 3')
    ];
    TabbedWiew tabbedView = TabbedWiew(
        controller: TabbedWiewController(tabs),
        closeButtonTooltip: 'Click here to close the tab');

Tab

Adding buttons

    TabData tab = TabData(text: 'Tab', buttons: [
      TabButton(icon: Icons.star, onPressed: () => print('Hello!'))
    ]);
    TabbedWiew tabbedView = TabbedWiew(controller: TabbedWiewController([tab]));

tabbutton

Overriding theme color

    var tabs = [
      TabData(text: 'Tab 1'),
      TabData(text: 'Tab 2', buttons: [
        TabButton(
            icon: Icons.star,
            color: Colors.green,
            onPressed: () => print('Hello!'))
      ])
    ];
    TabbedWiew tabbedView = TabbedWiew(controller: TabbedWiewController(tabs));

tabbuttoncolor

Removing the close button

    var tabs = [
      TabData(text: 'Tab'),
      TabData(text: 'Non-closable tab', closable: false)
    ];
    TabbedWiew tabbedView = TabbedWiew(controller: TabbedWiewController(tabs));

nonclosabletab

Close listener

    bool _onTabClosing(int tabIndex) {
      if (tabIndex == 0) {
        print('The tab $tabIndex is busy and cannot be closed.');
        return false;
      }
      print('Closing tab $tabIndex...');
      return true;
    }

    List<TabData> tabs = [
      TabData(text: 'Tab 1'),
      TabData(text: 'Tab 2'),
      TabData(text: 'Tab 3')
    ];
    TabbedWiew tabbedView = TabbedWiew(
        controller: TabbedWiewController(tabs), onTabClosing: _onTabClosing);

Selection listener

    _onTabSelection(int? newTabIndex) {
      print('The new selected tab is $newTabIndex.');
    }

    List<TabData> tabs = [
      TabData(text: 'Tab 1'),
      TabData(text: 'Tab 2'),
      TabData(text: 'Tab 3')
    ];
    TabbedWiew tabbedView = TabbedWiew(
        controller: TabbedWiewController(tabs),
        onTabSelection: _onTabSelection);

Draggable tab builder

    List<TabData> tabs = [];
    for (var i = 1; i < 7; i++) {
      Widget tabContent = Center(child: Text('Content $i'));
      tabs.add(TabData(text: 'Tab $i', content: tabContent));
    }
    TabbedWiew tabbedView = TabbedWiew(
        controller: TabbedWiewController(tabs),
        draggableTabBuilder: (int tabIndex, TabData tab, Widget tabWidget) {
          return Draggable<String>(
              child: tabWidget,
              feedback: Material(
                  child: Container(
                      child: Text(tab.text),
                      padding: EdgeInsets.all(4),
                      decoration: BoxDecoration(border: Border.all()))),
              data: tab.text,
              dragAnchorStrategy: (Draggable<Object> draggable,
                  BuildContext context, Offset position) {
                return Offset.zero;
              });
        });

Tabs area

Tabs area buttons

    TabbedWiewController controller = TabbedWiewController([]);

    TabbedWiew tabbedView = TabbedWiew(
        controller: controller,
        tabsAreaButtonsBuilder: (context, tabsCount) {
          List<TabButton> buttons = [];
          buttons.add(TabButton(
              icon: Icons.add,
              onPressed: () {
                int millisecond = DateTime.now().millisecondsSinceEpoch;
                controller.addTab(TabData(text: '$millisecond'));
              }));
          if (tabsCount > 0) {
            buttons.add(TabButton(
                icon: Icons.delete,
                onPressed: () {
                  if (controller.selectedIndex != null) {
                    controller.removeTab(controller.selectedIndex!);
                  }
                }));
          }
          return buttons;
        });

tabsareabuttons

Themes

Themes - Tab

Text style

    var tabs = [
      TabData(text: 'Tab 1'),
      TabData(text: 'Tab 2'),
    ];

    TabbedViewTheme theme = TabbedViewTheme.classic();
    theme.tabsArea.tab.textStyle = TextStyle(fontSize: 20, color: Colors.blue);

    TabbedWiew tabbedView =
        TabbedWiew(controller: TabbedWiewController(tabs), theme: theme);

tabtextstyle

Alignment

    var tabs = [
      TabData(text: 'Tab 1'),
      TabData(text: 'Tab 2'),
    ];

    TabbedViewTheme theme = TabbedViewTheme.classic();
    theme.tabsArea.tab
      ..textStyle = TextStyle(fontSize: 20)
      ..verticalAlignment = VerticalAlignment.top;

    TabbedWiew tabbedView =
        TabbedWiew(controller: TabbedWiewController(tabs), theme: theme);

topalignment

Themes - Tabs area

Color

  • The default TabsAreaTheme color is null.
    var tabs = [TabData(text: 'Tab 1'), TabData(text: 'Tab 2')];

    TabbedViewTheme theme = TabbedViewTheme.minimalist();
    theme.tabsArea.color = Colors.green[100];

    TabbedWiew tabbedView =
        TabbedWiew(controller: TabbedWiewController(tabs), theme: theme);

tabsareacolor

Tab gaps

  • Gap before the tabs (allows negative value).
  • Gap between tabs (allows negative value).
  • Minimum gap after tabs. Separates the last tab and the buttons area.
    List<TabData> tabs = [];
    for (var i = 1; i < 7; i++) {
      tabs.add(
          TabData(text: 'Tab $i', content: Center(child: Text('Content $i'))));
    }

    TabbedViewTheme theme = TabbedViewTheme.classic();
    theme.tabsArea
      ..initialGap = 20
      ..middleGap = 5
      ..minimalFinalGap = 5;

    TabbedWiew tabbedView =
        TabbedWiew(controller: TabbedWiewController(tabs), theme: theme);

customgap

Buttons area

Button icon for the hidden tabs menu
    List<TabData> tabs = [];
    for (var i = 1; i < 7; i++) {
      tabs.add(TabData(text: 'Tab $i'));
    }

    TabbedViewTheme theme = TabbedViewTheme.classic();
    theme.tabsArea.buttonsArea.hiddenTabsMenuButtonIcon =
        Icons.arrow_drop_down_circle_outlined;

    TabbedWiew tabbedView =
        TabbedWiew(controller: TabbedWiewController(tabs), theme: theme);

hiddentabsbuttonicon

Themes - Menu

Max width

    List<TabData> tabs = [];
    for (int i = 1; i < 11; i++) {
      tabs.add(TabData(text: 'Tab $i'));
    }

    TabbedViewTheme theme = TabbedViewTheme.classic()..menu.maxWidth = 100;

    TabbedWiew tabbedView =
        TabbedWiew(controller: TabbedWiewController(tabs), theme: theme);

menumaxwidth

Ellipsis on overflow text

    var tabs = [
      TabData(text: 'Tab 1'),
      TabData(text: 'Tab 2'),
      TabData(text: 'Tab 3'),
      TabData(
          text: 'The name of the tab is so long that it doesn'
              't fit on the menu')
    ];

    TabbedViewTheme theme = TabbedViewTheme.classic()
      ..menu.ellipsisOverflowText = true;

    TabbedWiew tabbedView =
        TabbedWiew(controller: TabbedWiewController(tabs), theme: theme);

menuellipsis

Predefined themes

Classic theme

    List<TabData> tabs = [];
    for (var i = 1; i < 7; i++) {
      tabs.add(TabData(text: 'Tab $i', content:  Center(child: Text('Content $i'))));
    }
    TabbedWiewController controller = TabbedWiewController(tabs);

    TabbedWiew tabbedView = TabbedWiew(
        controller: controller,
        theme: TabbedViewTheme.classic());

classic2

Classic theme - Color set
    List<TabData> tabs = [];
    for (var i = 1; i < 7; i++) {
      tabs.add(TabData(text: 'Tab $i', content:  Center(child: Text('Content $i'))));
    }
    TabbedWiewController controller = TabbedWiewController(tabs);

    TabbedViewTheme theme = TabbedViewTheme.classic(colorSet: Colors.green);

    TabbedWiew tabbedView = TabbedWiew(
        controller: controller,
        theme: theme);

classiccolorset

Dark theme

    List<TabData> tabs = [];
    for (var i = 1; i < 7; i++) {
      tabs.add(TabData(text: 'Tab $i'));
    }
    TabbedWiewController controller = TabbedWiewController(tabs);

    var contentBuilder = (BuildContext context, int index) {
      int i = index + 1;
      Text text = Text('Content $i', style: TextStyle(color: Colors.white));
      return Center(child: text);
    };

    TabbedWiew tabbedView = TabbedWiew(
        controller: controller,
        contentBuilder: contentBuilder,
        theme: TabbedViewTheme.dark());

    Container container = Container(child: tabbedView, color: Colors.black);

dark

Dark theme - Color set
    List<TabData> tabs = [];
    for (var i = 1; i < 7; i++) {
      tabs.add(TabData(text: 'Tab $i'));
    }
    TabbedWiewController controller = TabbedWiewController(tabs);

    var contentBuilder = (BuildContext context, int index) {
      int i = index + 1;
      Text text = Text('Content $i', style: TextStyle(color: Colors.white));
      return Center(child: text);
    };

    TabbedViewTheme theme = TabbedViewTheme.dark(colorSet: Colors.indigo);

    TabbedWiew tabbedView = TabbedWiew(
        controller: controller, contentBuilder: contentBuilder, theme: theme);

    Container container = Container(child: tabbedView, color: Colors.black12);

darkcolorset

Mobile theme

    TabbedWiew tabbedView =
        TabbedWiew(controller: controller, theme: TabbedViewTheme.mobile());

mobile

Mobile theme - Color set
    TabbedViewTheme theme = TabbedViewTheme.mobile(colorSet: Colors.blueGrey);
    TabbedWiew tabbedView = TabbedWiew(controller: controller, theme: theme);

mobilecolorset

Mobile theme - Highlighted tab color
    TabbedViewTheme theme =
        TabbedViewTheme.mobile(highlightedTabColor: Colors.green[700]!);
    TabbedWiew tabbedView = TabbedWiew(controller: controller, theme: theme);

mobilehighlightedcolor

Minimalist theme

    TabbedWiew tabbedView =
        TabbedWiew(controller: controller, theme: TabbedViewTheme.minimalist());

minimalist

Minimalist theme - Color set
    TabbedWiew tabbedView = TabbedWiew(
        controller: controller,
        theme: TabbedViewTheme.minimalist(colorSet: Colors.blue));

minimalistchangecolor

Creating new theme

It is possible to create an entire theme from scratch.

    var tabs = [
      TabData(text: 'Tab 1'),
      TabData(text: 'Tab 2'),
      TabData(text: 'Tab 3')
    ];

    TabbedViewTheme theme = TabbedViewTheme();
    theme.tabsArea
      ..border = Border(bottom: BorderSide(color: Colors.green[700]!, width: 3))
      ..middleGap = 6;

    Radius radius = Radius.circular(10.0);
    BorderRadiusGeometry? borderRadius =
        BorderRadius.only(topLeft: radius, topRight: radius);

    theme.tabsArea.tab
      ..padding = EdgeInsets.fromLTRB(10, 4, 10, 4)
      ..buttonsOffset = 8
      ..decoration = BoxDecoration(
          shape: BoxShape.rectangle,
          color: Colors.green[100],
          borderRadius: borderRadius)
      ..selectedStatus.decoration =
          BoxDecoration(color: Colors.green[200], borderRadius: borderRadius)
      ..highlightedStatus.decoration =
          BoxDecoration(color: Colors.green[50], borderRadius: borderRadius);

    TabbedWiew tabbedView =
        TabbedWiew(controller: TabbedWiewController(tabs), theme: theme);

fromthescratchcut

Libraries

tabbed_view