tabbed_view 1.8.0+1 tabbed_view: ^1.8.0+1 copied to clipboard
Flutter widget inspired by the classic Desktop-style tab component. Supports customizable themes.
Tabbed view #
Flutter widget inspired by the classic Desktop-style tab component. Supports customizable themes.
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));
}
TabbedView tabbedView = TabbedView(controller: TabbedViewController(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')
];
TabbedView tabbedView = TabbedView(
controller: TabbedViewController(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')
];
TabbedView tabbedView = TabbedView(
controller: TabbedViewController(tabs),
closeButtonTooltip: 'Click here to close the tab');
Tab #
Adding buttons #
Icon data
TabData tab = TabData(text: 'Tab', buttons: [
TabButton(
iconData: Icons.star,
onPressed: () => showSnackBar(context: context, msg: 'Hello!'))
]);
TabbedView tabbedView = TabbedView(controller: TabbedViewController([tab]));
// using material design icon patterns
TabbedViewThemeData themeData = TabbedViewThemeData.classic()
..materialDesign();
TabbedViewTheme theme = TabbedViewTheme(child: tabbedView, data: themeData);
Icon path
TabData tab = TabData(text: 'Tab', buttons: [
TabButton(
iconPath: _path,
onPressed: () => showSnackBar(context: context, msg: 'Hello!'))
]);
TabbedView tabbedView = TabbedView(controller: TabbedViewController([tab]));
Path _path(Size size) {
Path path = Path();
path.moveTo(size.width * 0.1, size.height * 0.1);
path.lineTo(size.width * 0.9, size.height * 0.1);
path.lineTo(size.width * 0.9, size.height * 0.9);
path.lineTo(size.width * 0.1, size.height * 0.9);
path.close();
return path;
}
Overriding theme color
var tabs = [
TabData(text: 'Tab', buttons: [
TabButton(
iconData: Icons.star,
color: Colors.green,
onPressed: () => showSnackBar(context: context, msg: 'Hello!'))
])
];
TabbedView tabbedView = TabbedView(controller: TabbedViewController(tabs));
// using material design icon patterns
TabbedViewThemeData themeData = TabbedViewThemeData.classic()
..materialDesign();
TabbedViewTheme theme = TabbedViewTheme(child: tabbedView, data: themeData);
Menu button
var tabs = [
TabData(text: 'Tab', buttons: [
TabButton(
iconPath: TabbedViewIcons.menu,
menuBuilder: (context) {
return [
TabbedViewMenuItem(
text: 'Menu item 1',
onSelection: () =>
showSnackBar(context: context, msg: 'menu item 1')),
TabbedViewMenuItem(
text: 'Menu item 2',
onSelection: () =>
showSnackBar(context: context, msg: 'menu item 2'))
];
})
])
];
TabbedView tabbedView = TabbedView(controller: TabbedViewController(tabs));
Non-closable tab #
var tabs = [
TabData(text: 'Tab'),
TabData(text: 'Non-closable tab', closable: false)
];
TabbedView tabbedView = TabbedView(controller: TabbedViewController(tabs));
Close interceptor #
bool _tabCloseInterceptor(int tabIndex) {
if (tabIndex == 0) {
print('The tab $tabIndex is busy and cannot be closed.');
return false;
}
return true;
}
List<TabData> tabs = [
TabData(text: 'Tab 1'),
TabData(text: 'Tab 2'),
TabData(text: 'Tab 3')
];
TabbedView tabbedView = TabbedView(
controller: TabbedViewController(tabs),
tabCloseInterceptor: _tabCloseInterceptor);
Close listener #
List<TabData> tabs = [
TabData(text: 'Tab 1'),
TabData(text: 'Tab 2'),
TabData(text: 'Tab 3')
];
TabbedView tabbedView = TabbedView(
controller: TabbedViewController(tabs),
onTabClose: (index, tabData) {
print('$index: ' + tabData.text);
});
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')
];
TabbedView tabbedView = TabbedView(
controller: TabbedViewController(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));
}
TabbedView tabbedView = TabbedView(
controller: TabbedViewController(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;
});
});
Keep alive #
The keepAlive
parameter indicates whether to keep the tab content widget in memory even if it is not visible. Indicated to prevent loss of state due to tree change by tab selection. If enabled, the Widget will continue to be instantiated in the tree but will remain invisible. The default value is FALSE
.
Tabs area #
Tabs area buttons #
TabbedViewController controller = TabbedViewController([]);
TabbedView tabbedView = TabbedView(
controller: controller,
tabsAreaButtonsBuilder: (context, tabsCount) {
List<TabButton> buttons = [];
buttons.add(TabButton(
iconData: Icons.add,
onPressed: () {
int millisecond = DateTime.now().millisecondsSinceEpoch;
controller.addTab(TabData(text: '$millisecond'));
}));
if (tabsCount > 0) {
buttons.add(TabButton(
iconData: Icons.delete,
onPressed: () {
if (controller.selectedIndex != null) {
controller.removeTab(controller.selectedIndex!);
}
}));
}
return buttons;
});
// using material design icon patterns
TabbedViewThemeData themeData = TabbedViewThemeData.classic()
..materialDesign();
TabbedViewTheme theme = TabbedViewTheme(child: tabbedView, data: themeData);
Themes #
Themes - Tab #
Text style
var tabs = [
TabData(text: 'Tab 1'),
TabData(text: 'Tab 2'),
];
TabbedView tabbedView = TabbedView(controller: TabbedViewController(tabs));
TabbedViewThemeData themeData = TabbedViewThemeData.classic()
..tab.textStyle = TextStyle(fontSize: 20, color: Colors.blue);
TabbedViewTheme theme = TabbedViewTheme(child: tabbedView, data: themeData);
Alignment
var tabs = [
TabData(text: 'Tab 1'),
TabData(text: 'Tab 2'),
];
TabbedView tabbedView = TabbedView(controller: TabbedViewController(tabs));
TabbedViewThemeData themeData = TabbedViewThemeData.classic();
themeData.tab
..textStyle = TextStyle(fontSize: 20)
..verticalAlignment = VerticalAlignment.top;
TabbedViewTheme theme = TabbedViewTheme(child: tabbedView, data: themeData);
Themes - Tabs area #
Color
TabbedView tabbedView = TabbedView(controller: controller);
TabbedViewThemeData themeData = TabbedViewThemeData.classic();
themeData.tabsArea.color = Colors.green[100];
TabbedViewTheme theme = TabbedViewTheme(child: tabbedView, data: themeData);
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.
TabbedView tabbedView = TabbedView(controller: controller);
TabbedViewThemeData themeData = TabbedViewThemeData.classic();
themeData.tabsArea
..initialGap = 20
..middleGap = 5
..minimalFinalGap = 5;
TabbedViewTheme theme = TabbedViewTheme(child: tabbedView, data: themeData);
Buttons area
Button icon for the hidden tabs menu
TabbedView tabbedView = TabbedView(controller: controller);
TabbedViewThemeData themeData = TabbedViewThemeData.classic()
..materialDesign()
..tabsArea.menuIconData = Icons.arrow_drop_down_circle_outlined;
TabbedViewTheme theme = TabbedViewTheme(child: tabbedView, data: themeData);
Themes - Menu #
Max width
TabbedView tabbedView = TabbedView(controller: controller);
TabbedViewThemeData themeData = TabbedViewThemeData.classic()
..menu.maxWidth = 100;
TabbedViewTheme theme = TabbedViewTheme(child: tabbedView, data: themeData);
Ellipsis on text overflow
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')
];
TabbedViewController controller = TabbedViewController(tabs);
TabbedView tabbedView = TabbedView(controller: controller);
TabbedViewThemeData themeData = TabbedViewThemeData.classic()
..menu.ellipsisOverflowText = true;
TabbedViewTheme theme = TabbedViewTheme(child: tabbedView, data: themeData);
Default themes #
Classic theme
TabbedView tabbedView = TabbedView(controller: controller);
TabbedViewTheme theme =
TabbedViewTheme(child: tabbedView, data: TabbedViewThemeData.classic());
Classic theme - Color set
TabbedView tabbedView = TabbedView(controller: controller);
TabbedViewTheme theme = TabbedViewTheme(
child: tabbedView,
data: TabbedViewThemeData.classic(colorSet: Colors.green));
Dark theme
TabbedView tabbedView = TabbedView(controller: controller);
TabbedViewTheme theme =
TabbedViewTheme(child: tabbedView, data: TabbedViewThemeData.dark());
Dark theme - Color set
TabbedView tabbedView = TabbedView(controller: controller);
TabbedViewTheme theme = TabbedViewTheme(
child: tabbedView,
data: TabbedViewThemeData.dark(colorSet: Colors.indigo));
Mobile theme
TabbedView tabbedView = TabbedView(controller: controller);
TabbedViewTheme theme =
TabbedViewTheme(child: tabbedView, data: TabbedViewThemeData.mobile());
Mobile theme - Color set
TabbedView tabbedView = TabbedView(controller: controller);
TabbedViewTheme theme = TabbedViewTheme(
child: tabbedView,
data: TabbedViewThemeData.mobile(colorSet: Colors.blueGrey));
Mobile theme - Highlighted tab color
TabbedView tabbedView = TabbedView(controller: controller);
TabbedViewTheme theme = TabbedViewTheme(
child: tabbedView,
data: TabbedViewThemeData.mobile(
highlightedTabColor: Colors.green[700]!));
Minimalist theme
TabbedView tabbedView = TabbedView(controller: controller);
TabbedViewTheme theme = TabbedViewTheme(
child: tabbedView, data: TabbedViewThemeData.minimalist());
Minimalist theme - Color set
TabbedView tabbedView = TabbedView(controller: controller);
TabbedViewTheme theme = TabbedViewTheme(
child: tabbedView,
data: TabbedViewThemeData.minimalist(colorSet: Colors.blue));
Theme from scratch #
It is possible to create an entire theme from scratch.
var tabs = [
TabData(text: 'Tab 1'),
TabData(text: 'Tab 2'),
TabData(text: 'Tab 3')
];
TabbedViewController controller = TabbedViewController(tabs);
TabbedView tabbedView = TabbedView(controller: controller);
TabbedViewThemeData themeData = TabbedViewThemeData();
themeData.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);
themeData.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);
TabbedViewTheme theme = TabbedViewTheme(child: tabbedView, data: themeData);