Flutter project. I have a bottomNavigationBar, style=fixed. It has 4 items and it works fine. However, I need a way to unselect all items on this bar. It seems that it has to always have exactly 1 item selected, which generally makes sense, but for my project there are some instances where I need to have 0 items selected.
I can fake this by changing the color of the icon and text to be the same color of the inactive items, and that pretty much looks inactive, except the icon and text are slightly larger since it really is still selected.
Is there a way to actually unselect all items in a bottomNavigationBar instead of just trying to make them appear to be unselected?
Unfortunately, there is no way to set all bottom navbar items as unselected. At a time, one of them should be set as selected.
As you also suggested, the only workaround is to make all items look like "unselected" by setting style properties like selectedItemColor, etc. of BottomNavigationBar.
Unfortunately, it is impossible but there is a trick:
int _selectedIndex = -1;// Unselect any item
....
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
// This is all you need!
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.support),
label: 'support',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'business',
),
BottomNavigationBarItem(
icon: Icon(Icons.text_snippet_sharp),
label: 'Report',
),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle_outlined),
label: 'Account',
),
],
currentIndex: selectedIndex == -1 ? 0: selectedIndex,
selectedItemColor: selectedIndex == -1 ? Colors.grey[600] : Colors.amber[800],
unselectedItemColor: Colors.grey[600],
onTap: onTap,
);
You could use something like this:
bottomNavigationBar: BottomNavigationBar(
items: getBottomNavigationBarItems(),
currentIndex: _currentPage < 4 ? _currentPage : 0,
showSelectedLabels:_currentPage < 4,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
Related
I want to mark the ListTile of the current page as selected but 2 days ago I'm looking for a general way to do it.
I saw examples like this one where you hardcode the tile ID and use a case to know which is the current Tile. My question is, what if I have, to exaggerate, 100 ListTiles? How do I change the selected attribute programmatically to the selected Tile? Or a more real case: I have a Drawer that changes shape in each release, so keeping a code with the hardcoded IDs is not useful. I hope you understand the idea.
I've been trying different solutions for days but none seems general enough to me.
Simple create enum class like below.
enum DrawerSelection { home, favorites, settings}
Create enum object and pass pre-defined value if you want, in my case i pass home as selected ListTile item. Like below code.
class _MyHomePage extends State<MyHomePage> {
DrawerSelection _drawerSelection = DrawerSelection.home;
Then in ListTile use selected property and change enum onTap() like below code.
ListTile(
selected: _drawerSelection == DrawerSelection.home,
title: Text('Home'),
leading: Icon(Icons.home),
onTap: () {
Navigator.pop(context);
setState(() {
_drawerSelection = DrawerSelection.home;
_currentWidget = MainWidget();
_appBarTitle = Text("Home");
});
},
),
ListTile(
selected: _drawerSelection == DrawerSelection.favorites,
title: Text('Favorites'),
leading: Icon(Icons.favorite),
onTap: () {
Navigator.pop(context);
setState(() {
_drawerSelection = DrawerSelection.favorites;
_currentWidget = FavoritesWidget();
_appBarTitle = Text("Favorites");
});
},
),
ListTile(
selected: _drawerSelection == DrawerSelection.settings,
title: Text('Settings'),
leading: Icon(Icons.settings),
onTap: () {
Navigator.pop(context);
setState(() {
_drawerSelection = DrawerSelection.settings;
_currentWidget = SettingsWidget();
_appBarTitle = Text("Settings");
});
},
),
i think it is just simple you can create a new class that have your data and the bool selected
class Post {
final bool selected;
var data;
Post({
this.selected,
this.data
});
}
now when you use LIstView.builder in the itemBuilder if list[index].selected is true then set the color to blue if not then let it white or whatever in the on tap or onpressed whatever you are you using save the last clicked index in a global variable(called savedIndex)-initialize it with (-1)- and change selected to true at the this list index,then if savedIndex wasnt equal -1 change list[savedIndex].selected=false.
global variable
int selectedIndex =-1;
and itemBuilder.
itemBuilder: (BuildContext _context, int i) {
return GestureDetector(
child:
Container(
decoration: new BoxDecoration(
borderRadius: new BorderRadius.circular(16.0),
color:_list[index].selected? Colors.blue:colors.white,
),
child: _buildRow(_list[index]),) ,
onTap: () {
setState(){
if(savedIndex!=-1){
list[savedIndex].selected=false
}
_list[index].selected=true;
savedIndex=index;
}
}
);
}
how do I test BottomNavigationBarItems via FlutterDriver?
FlutterDriver allows accessing Widgets via text, byValueKey, byTooltip and byType.
But none of these methods work out for my App because of following reasons:
text: The App is localized and I need to test the App in multiple languages.
byValueKey: BottomNavigationBarItems do not have key properties.
byTooltip: BottomNavigationBarItems do not have toolTip properties.
byType: byType only returns the first match of the type and no list (needed because I have multiple tabs).
Thank you very much!
Cheers.
Not sure if you have found answer for this question, but I am going to post a solution here which works for me. Basically, BottomNavigationBar has a key property which you need to use. Once Flutter Driver identifies this key, then you can tell driver to tap on any of its child items ie BottomNavigationBarItem.
My screen has 2 bottomNavigationBarItems as shown below and I defined key for their parent widget ie BottomNavigationBar as:
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.shifting,
key: Key('bottom'),
items: [
BottomNavigationBarItem(
icon: Icon(Icons.ac_unit, color: Colors.green,),
title: Text('First', style: TextStyle(color: Colors.black),)
),
BottomNavigationBarItem(
icon: Icon(Icons.cast, color: Colors.yellow,),
title: Text('Second', style: TextStyle(color: Colors.black),)
)
],
),
And I wrote a flutter driver test to tap on both items which worked perfectly.
test('bottomnavigationbar test', () async {
await driver.waitFor(find.byValueKey('bottom'));
await driver.tap(find.text('First'));
print('clicked on first');
await driver.tap(find.text('Second'));
print('clicked on second too');
});
Result:
As mentioned by #bsr and #user12563357- you can use the key on Text widget:
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.shifting,
key: Key('bottom'),
items: [
BottomNavigationBarItem(
icon: Icon(Icons.ac_unit),
title: Text('First', key: Key('first'),)
),
BottomNavigationBarItem(
icon: Icon(Icons.cast),
title: Text('Second', key: Key('second'),)
)
],
),
and find the text to click on the bar item in test:
final firstItem = find.byValueKey('first');
await driver.tap(firstItem);
btw: you can also find BottomNavigationBarItem using find.ancestor
find.ancestor(of: firstItem, matching: find.byType("BottomNavigationBarItem"));
but you can't tap on it.
You have two options - byIcon or with text by getting the localization from the context.
You can get the state of any kind of StatefulWidget.
final MyWidgetState state = tester.state(find.byType(MyWidget));
with this you can get the context and with that the current localizaion.
final l10n = AppLocalizations.of(state.context);
await tester.tap(find.text(l10n.youTitle));
One other option is to get the widget by Icon:
await tester.tap(find.byIcon(Icons.your_icon));
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.shifting,
key: Key(`bottom`),
items: [
BottomNavigationBarItem(
icon: Icon(Icons.ac_unit, color: Colors.green,),
title: InkWell(child:Text(`First`, style: TextStyle(color: Colors.black),key:Key(`First`)),)
),
BottomNavigationBarItem(
icon: Icon(Icons.cast, color: Colors.yellow,),
title: InkWell(child:Text(`Second`, style: TextStyle(color: Colors.black),key:Key(`Second`)),)
)
],
),
test(`bottomnavigationbar test`, () async {
await driver.waitFor(find.byValueKey(`bottom`));
await driver.tap(find.byValueKey(`First`));
print('clicked on first');
await driver.tap(find.byValueKey(`Second`));
print('clicked on second too');
});
Is it possible to make the secondary property of the SwitchListTile tapable? In this case, an icon is used:
SwitchListTile(
title: const Text('Lights'),
value: _lights,
onChanged: (bool value) { setState(() { _lights = value; }); },
secondary: const Icon(Icons.lightbulb_outline), //can this be selected?
)
Ideally, instead of creating another widget, I would like to use the Icon in the secondary property to display a message when the user selects it.
Currently when the icon, or entire widget is selected, the switch is toggled. What is the best way to handle this action?
Thanks.
Wrap your Icon inside InkWell to handle the tap :
secondary: InkWell(
onTap: () {
print("click light");
},
child: const Icon(Icons.lightbulb_outline),
),
More info here: https://docs.flutter.io/flutter/material/InkWell-class.html
You could wrap your Icon in an IconButton.
SwitchListTile(
title: const Text('Lights'),
value: _lights,
onChanged: (value) => setState(() => _lights = value),
secondary: IconButton(
icon: Icon(Icons.lightbulb_outline),
onPressed: () {},
),
)
I've inserted custom icons into my application and when I run the app, the icons and text are white, instead of the original color.
Two Problems:
1)The Icons are originally black but when I insert it to my Bottom Nav Items they become white.
2)Also only the first item has a tittle beneath the icon the rest doesn't.
This is my code
bottomNavigationBar: BottomNavigationBar(
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(const IconData(0xe903, fontFamily: 'navBar')),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(const IconData(0xe902, fontFamily: 'navBar')),
title: Text('Ideas')
),
BottomNavigationBarItem(
icon: Icon(const IconData(0xe903, fontFamily: 'navBar')),
title: Text('Profile')
),
BottomNavigationBarItem(
icon: Icon(const IconData(0xe901, fontFamily: 'navBar')),
title: Text('Bag')
),
],
),
//pubspec.yaml file
fonts:
- family: navBar
fonts:
- asset: assets/fonts/ic_navbar.ttf
The 4 icons
You need to add a type for your ButtomNavigationBar
bottomNavigationBar: BottomNavigationBar(
//Add this line will fix the issue.
type: BottomNavigationBarType.fixed,
currentIndex: 0, // this will be set when a new tab is tapped
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: new Icon(const IconData(0xe903, fontFamily: 'navBar')),
title: new Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(const IconData(0xe902, fontFamily: 'navBar')),
title: new Text('Messages'),
),
BottomNavigationBarItem(
icon: Icon(const IconData(0xe903, fontFamily: 'navBar')),
title: Text('Profile'),
),
BottomNavigationBarItem(
icon: Icon(const IconData(0xe901, fontFamily: 'navBar')),
title: Text('Bag')
),
],
),
You can use the following code to change the icon color in bottom navigation bar
BottomNavigationBarItem(
icon:IconTheme(child: Icon(Icons.date_range),
data:IconThemeData(color:Colors.yellow)),
title:Text('Schedule')
)
Though it is a rather old thread I wanted to share a finding regarding this topic because I was in the same situation. According to flutter documentation it is expected behavior that item colors default is white if there are more than 3 items in the bottomnavigationbar and there is no selectedItemColor.
BottomNavigationBarType.shifting, the default when there are four or more items. If selectedItemColor is null, all items are rendered in white. The navigation bar's background color is the same as the BottomNavigationBarItem.backgroundColor of the selected item. In this case it's assumed that each item will have a different background color and that background color will contrast well with white.
Flutter Api reference
try the icons that come in the material icons, https://docs.flutter.io/flutter/material/Icons-class.html to make a kind of debug, if the error continues the error is in another side, can you send all the code and send the assets you use?enter image description here
I am trying to change the selected color of a BottomNavigation icon but all I seem to be achieving is changing the text colours. Please assist:
Currently the text color changes to yellow when selected but the icon stays white, I want it to be yellow too and I have tried setting the icon color of the inactive icons to grey like the caption but it's not budging.
Here is my code:
new Theme(
data: Theme.of(context).copyWith(
canvasColor: Colors.black,
splashColor: Colors.yellowAccent,
unselectedWidgetColor: Colors.green,
primaryColor: Colors.red,
textTheme: Theme.of(context).textTheme.copyWith(caption: new TextStyle(color: Colors.grey))
),
child: new BottomNavigationBar(
items: <BottomNavigationBarItem>[
new BottomNavigationBarItem(
icon: const Icon(Icons.add_shopping_cart, color: Colors.white,),
title: new Text("Services"),
),
new BottomNavigationBarItem(
icon: new Theme(
data: new ThemeData(
),
child: const Icon(Icons.calendar_today, color: Colors.white,)),
title: new Text("Appointment")
),
new BottomNavigationBarItem(
icon: const Icon(Icons.face, color: Colors.white,),
title: new Text("Profile")
)
],
currentIndex: index,
onTap: (int i){setState((){index = i;});},
fixedColor: Colors.yellowAccent,
type: BottomNavigationBarType.fixed,
),
)
Don't declare the color of icon inside BottomNavigationBarItem.
You should declare it inside BottomNavigationBar as unselectedItemColor and selectedItemColor.
bottomNavigationBar:
BottomNavigationBar(
unselectedItemColor: Colors.green,
selectedItemColor: Colors.yellow,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.add_shopping_cart),
),
],
);
By doing so, your code will work.
You've explicitly set color: Colors.white for each of the icons, so they will be white until you set them otherwise.
You have a couple of options:
1) Set your BottomNavigationBar's type to type: BottomNavigationBarType.fixed and set fixedColor: Colors.orange or whatever color you want. Note that you'll have to remove your color: Colors.white or they will still be white.
2) You could test for the right index being set and then decide which color to set the icon to directly, i.e. color = index == 0 ? selectedColor : unselectedColor for the first item, index==1 for the second, and item==2 for the third.
3) A slight alternative would be to set an IconTheme with color=unselectedColor around the entire BottomNavigationBar, then only set the selected item with color = index == 0 ? selectedColor : null.
I'd recommend reading the BottomNavigationBar documentation, particularly the part about fixed vs shifting, as it describes the answer to the exact problem you're having.
This how you could set the color of the icon:
bottomNavigationBar: BottomNavigationBar(
selectedIconTheme: IconThemeData(color: Colors.yellow),
unselectedIconTheme: IconThemeData(color: Colors.white),