keyed_collection_widgets 0.3.1 keyed_collection_widgets: ^0.3.1 copied to clipboard
BottomNavigationBar, IndexedStack, and TabController that use item keys instead of indexes.
These are replacements to BottomNavigationBar
, IndexedStack
, and TabController
that use
item keys instead if numeric indexes.
Problem #
With traditional widgets you write something like
const tabFavorites = 0;
const tabSearch = 1;
// ...
if (tabIndex == tabFavorites) {
// ...
}
If items in your bar can change, you get an error-prone conversion from indexes to meanings.
Also with mature architecture you tend to use enum
for your tabs, and even with constant bar items
you must write code to convert between enum
and int
.
Usage #
With this package you can use your enum
directly with collection widgets.
See the full runnable example in the example
folder.
KeyedBottomNavigationBar and KeyedStack #
enum MyTab {favorites, search}
class _MyHomeScreenState extends State<MyHomeScreen> {
MyTab _tab = MyTab.favorites;
@override
Widget build(BuildContext context) {
// This is a simplified example: IndexedStack and KeyedStack are only
// meaningful if they contain stateful widgets to preserve state
// between switches.
return Scaffold(
body: KeyedStack<MyTab>(
itemKey: _tab,
children: const {
MyTab.favorites: Center(child: Text('Favorites')),
MyTab.search: Center(child: Text('Search')),
},
),
bottomNavigationBar: KeyedBottomNavigationBar<MyTab>(
currentItemKey: _tab,
items: const {
MyTab.favorites: BottomNavigationBarItem(
icon: Icon(Icons.star),
label: 'Favorites',
),
MyTab.search: BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Search',
),
},
onTap: (tab) => setState((){ _tab = tab; }),
),
);
}
}
KeyedTabController, KeyedTabBar, KeyedTabBarView #
enum MyTab {one, two, three}
class _MyHomeScreenState extends State<MyHomeScreen> with TickerProviderStateMixin {
late final KeyedTabController<MyTab> _tabController;
@override
void initState() {
super.initState();
_tabController = KeyedTabController<MyTab>(
initialKey: MyTab.three,
keys: [MyTab.one, MyTab.two, MyTab.three],
vsync: this,
);
}
@override
Widget build(BuildContext context) {
return Column(
children: [
KeyedTabBar(
tabs: {
for (final key in _tabController.keys)
key: Tab(child: Text(key.toString())),
},
controller: _tabController,
labelColor: Theme.of(context).colorScheme.secondary,
),
Expanded(
child: KeyedTabBarView(
children: {
for (final key in _tabController.keys)
key: Text("$key content"),
},
controller: _tabController,
),
),
],
);
}
}
Some more advantages of enum
over indexes:
- No way for the value to fall out of range.
- Easier debugging with IDE tools.
- You will never use magic numbers for indexes.
KeyedBottomNavigationBar
and KeyedStack
support all the arguments of their traditional counterparts.
The only difference is that current keys are required and do not default to first element.