Flutter widget inspired by the classic Desktop-style tab component. Supports customizable themes.
The TabbedView renders the presentation of the model.
The TabbedViewModel stores the tab data as name, content, buttons or any dynamic value.
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));
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
Extra button
TabData tab = TabData(text: 'Tab', buttons: [
TabButton(icon: Icons.star, onPressed: () => print('Hello!'))
]);
TabbedWiew tabbedView = TabbedWiew(controller: TabbedWiewController([tab]));
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));
Removing the close button
var tabs = [
TabData(text: 'Tab'),
TabData(text: 'Non-closable tab', closable: false)
];
TabbedWiew tabbedView = TabbedWiew(controller: TabbedWiewController(tabs));
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);
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;
});
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);
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);
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);
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);
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);
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);
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);
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());
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);
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);
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);
Mobile theme
TabbedWiew tabbedView =
TabbedWiew(controller: controller, theme: TabbedViewTheme.mobile());
Color set
TabbedViewTheme theme = TabbedViewTheme.mobile(colorSet: Colors.blueGrey);
TabbedWiew tabbedView = TabbedWiew(controller: controller, theme: theme);
Highlighted tab color
TabbedViewTheme theme =
TabbedViewTheme.mobile(highlightedTabColor: Colors.green[700]!);
TabbedWiew tabbedView = TabbedWiew(controller: controller, theme: theme);
Minimalist theme
TabbedWiew tabbedView =
TabbedWiew(controller: controller, theme: TabbedViewTheme.minimalist());
Color set
TabbedWiew tabbedView = TabbedWiew(
controller: controller,
theme: TabbedViewTheme.minimalist(colorSet: Colors.blue));
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);
Agenda for the next few days
- Complete documentation and examples to cover all available features.
- Release the final version (1.0.0). The API may have some small changes.