I am creating a bottom navigation bar in flutter. I would like to pick the labels from an array. The following program throws an error "Values in a const list literals must be constants". I understand that the the list of navigation bar items in the scaffold is declared const and we cannot use the non-const string arrays. How to fix this problem?
class _MyHomePageState extends State<MyHomePage> {
int _currentIndex = 0;
// final List _children = [];
Text titleText = new Text('Pensor');
var tabLabels = ['Home', 'Water', 'Insights', 'Cabliration', 'Settings'];
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
title: titleText,
),
// body: _children[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
onTap: onTabTapped,
currentIndex: _currentIndex,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: tabLabels[0], // <-- Here is the error. The tabLabels are not const.
),
BottomNavigationBarItem(
icon: Icon(Icons.water_damage),
label: 'Water',
),
BottomNavigationBarItem(
icon: Icon(Icons.insights),
label: 'Insights',
),
BottomNavigationBarItem(
icon: Icon(Icons.biotech),
label: 'Calibration',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Settings',
),
],
),
);
}
Just remove const
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: tabLabels[0],
),
BottomNavigationBarItem(
icon: Icon(Icons.water_damage),
label: 'Water',
),
BottomNavigationBarItem(
icon: Icon(Icons.insights),
label: 'Insights',
),
BottomNavigationBarItem(
icon: Icon(Icons.biotech),
label: 'Calibration',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Settings',
),
],
Related
List navScreens = [
const HomeScreen(),
const FavoriteScreen(),
const NotificationScreen(),
const MyProfilesScreen(),
];
Scaffold(
body: navScreens.elementAt(selectedIndex),
bottomNavigationBar: BottomNavigationBar(
currentIndex: selectedIndex,
iconSize: 34,
selectedItemColor: ConstColors.green,
unselectedItemColor: ConstColors.black2,
elevation: 10,
onTap: (value) {
setState(() {
selectedIndex = value;
});
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home_outlined), label: 'home'),
BottomNavigationBarItem(
icon: Icon(Icons.bookmark_border_outlined), label: 'favorite'),
BottomNavigationBarItem(
icon: Icon(Icons.notifications_none), label: 'notification'),
BottomNavigationBarItem(
icon: Icon(Icons.person_outline), label: 'profile'),
],
),
);
When I switch screens from BottomNavBar (MainScreen) to inside (DetailScreen), then BottomNavBar disappears. If I directly navigate to bottombar screen back from nested screens. It also get disappear. Persistent_bottom_bar is another solution but I want to fix it with built in support. Thanks !
This package suits your need well.
I would like to use Navigator.pushNamed(context, '/route-name'); instead of creating an object instance. I'm trying to get back to a single instance of the called screen from multiple screens of the app. Is there any other way to make this possible?
I would like to replace the widget list with navigator routes instances so I can navigate back to my screen from any place in the app. Code below:
class _NavigationWrapperState extends State<NavigationWrapper> {
var bottomWidgetKey = GlobalKey<State<BottomNavigationBar>>();
int _index = 0;
List<Widget> widgets = [
MyIssuesOverview(),
ProjectOverview(),
DashboardWrapper(),
SettingsScreen(),
];
#override
Widget build(BuildContext context) {
return Scaffold(
key: bottomWidgetKey,
body: widgets.elementAt(_index),
bottomNavigationBar: BottomNavigationBar(
selectedItemColor: Colors.blue,
unselectedItemColor: Colors.grey,
onTap: (int idx) => {
setState(() {
_index = idx;
}),
},
currentIndex: _index,
items: [
BottomNavigationBarItem(label: "Home", icon: Icon(Icons.home)),
BottomNavigationBarItem(label: "Projects", icon: Icon(Icons.topic)),
BottomNavigationBarItem(
label: "Dashboard",
icon: Icon(Icons.add_chart),
),
BottomNavigationBarItem(
label: "Timer",
icon: Icon(Icons.lock_clock),
),
BottomNavigationBarItem(
label: "Settings",
icon: Icon(Icons.settings),
)
],
),
);
}
}
context: my app navigation relies on one screen with a scaffold and a BottomNavigationBar containing BottomNavigationBarItems. If you click an item, its index dertermines which widget is picked from a list to serve as body for the scaffold. (Code below)
problem: I'd also like to add a Drawer to the scaffold that can also be used for navigation. I know how to add a drawer, but I don't know how to connect items in there with my navigation.
solution I can see:
I could try writing my own function that determines the index of whatever I click in the drawer and sets my page selection to that index. I don't want to reinvent the wheel though; Is there anything like the combination of "BottomNavigationBar + BottomNavigationBarItems" I could place in the drawer? Am I thinking about this the wrong way?
EDIT: I can also just add a list of items wrapped in individual GestureDetectors and call _selectPage() with a hard coded index ... but that does feel clumsy.
Shortened code of the screen for the tabbed navigation:
class _TabsScreenState extends State<TabsScreen> with WidgetsBindingObserver {
late List<Widget> _pages;
late Timer timer;
int _selectedPageIndex = 0;
#override
void initState() {
_pages = [
HomeScreen(),
FavoritesScreen(),
LookBackScreen(),
InfoScreen(),
];}
void _selectPage(int index) {
setState(() {
_selectedPageIndex = index;
});
}
return Scaffold(
appBar: AppBar(
//
body: _pages[_selectedPageIndex],
//
bottomNavigationBar: BottomNavigationBar(
onTap: _selectPage,
currentIndex: _selectedPageIndex,
type: BottomNavigationBarType.fixed,
items: [
//home
BottomNavigationBarItem(
icon: Icon(Icons.home, color: customColorScheme['Icon 1']),
activeIcon: Icon(Icons.home, color: customColorScheme['Icon 2']),
label: '',
),
//favorite
BottomNavigationBarItem(
icon: Icon(Icons.favorite, color: customColorScheme['Icon 1']),
activeIcon:
Icon(Icons.favorite, color: customColorScheme['Icon 2']),
label: '',
),
//loockback
BottomNavigationBarItem(
icon: Icon(Icons.bar_chart, color: customColorScheme['Icon 1']),
activeIcon:
Icon(Icons.bar_chart, color: customColorScheme['Icon 2']),
label: '',
),
//info & support
BottomNavigationBarItem(
icon: Icon(Icons.info, color: customColorScheme['Icon 1']),
activeIcon: Icon(Icons.info, color: customColorScheme['Icon 2']),
label: '',
),
],
),
);
}
}
Is there a way that I can make an item on bottom navigation bar unclickable that doesn't route anywhere?
lets say you want to deactivate deactiveIndex in your navigation bar. use this:
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Business',
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'School',
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap:(index){
if(index == deactiveIndex){ return;}
setState((){_selectedIndex=index});
},
),
for more UI representation you can set activeIcon for active indices or change the color and style of reactive index.
I'm creating this app, and I added a bottom navigation bar, and everything is working just fine, except the background color. I would like the background to change depending which item has been selected. It works just fine when I use type: BottomNavigationBarType.shifting, but not when I change it to type: BottomNavigationBarType.fixed.
The thing is that I don't like the "shifting" behavior, I prefer it "fixed".
I found this example online, but it uses the shifting type:
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
backgroundColor: Colors.teal
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile',
backgroundColor: Colors.cyan
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Settings',
backgroundColor: Colors.lightBlue,
),
],
type: BottomNavigationBarType.shifting,
currentIndex: _selectedIndex,
selectedItemColor: Colors.white,
unselectedItemColor: Colors.grey,
iconSize: 40,
onTap: _onItemTap,
elevation: 5
)
How could I achieve the same background color changing effect using a bottom navigation bar using type: BottomNavigationBarType.fixed?
Thanks in advance.
Use BackgroundNavigationBar.backgroundColor. Consider this modified example from the docs:
class Option {
final String name;
final IconData icon;
final Color color;
const Option({
required this.name,
required this.icon,
required this.color,
});
}
class HomePageState extends State<HomePage> {
static const List<Option> options = [
Option(name: "Home", icon: Icons.home, color: Colors.red,),
Option(name: "Business", icon: Icons.business, color: Colors.green),
Option(name: "School", icon: Icons.school, color: Colors.purple),
Option(name: "Settings", icon: Icons.settings, color: Colors.pink),
];
int index = 0;
Option get option => options [index];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: Center(
child: Text("Index $index: ${option.name}"),
),
bottomNavigationBar: BottomNavigationBar(
backgroundColor: option.color,
type: BottomNavigationBarType.fixed,
currentIndex: index,
onTap: (value) => setState(() => index = value),
items: [
for (final option in options) BottomNavigationBarItem(
icon: Icon(option.icon),
label: option.name,
),
],
),
);
}
}