Reputation: 51
Trying to activate CupertinoTabBar's
tab 0 while tab 1 is active on a stream event
like this:
{
class HomeScreen extends StatefulWidget {
@override
State<StatefulWidget> createState() => HomeScreenState();
}
class HomeScreenState extends State<HomeScreen> {
int _currentTabIndex = 0;
@override
void initState() {
super.initState();
_drawerStream.listen((state) {
if (_currentTabIndex != 0) {
SchedulerBinding.instance.addPostFrameCallback((_) {
setState(() => _currentTabIndex = 0);
});
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: Drawer(
elevation: 0.0,
child: DrawerScreen(),
),
body: CupertinoTabScaffold(
tabBar: CupertinoTabBar(
onTap: (index) {
_currentTabIndex = index;
},
currentIndex: _currentTabIndex,
backgroundColor: Colors.white,
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
title: Text('Main'),
icon: Icon(IconData(0xe800), size: 20),
),
BottomNavigationBarItem(
title: Text('Goodies'),
icon: Icon(IconData(0xe84b), size: 20),
),
],
),
tabBuilder: (BuildContext context, int index) {
return CupertinoTabView(
builder: (BuildContext context) {
switch (index) {
case 0: return MainScreen();
case 1: return GoodiesScreen();
}
},
);
},
),
);
}
}
}
It nothing happens visually when an event comes from _drawerStream
. Still tracing what's going on using the debugger it found that CupertinoTabBar
widget builds 2 times and 1st time it has current index parameter 0, what we actually need. But the second run it rebuilds with current index parameter set to 1, which is not what we want.
What the reason for that, how we can switch to a tab on an external event?
Upvotes: 1
Views: 2208
Reputation: 2284
You can also use GlobalKeys and your problem should go away. Here is a clear tutorial on how to do it
https://medium.com/@info_4766/ios-tab-bar-in-flutter-9379cf09df31
Upvotes: 0
Reputation: 51
It's solved using StreamBuilder, a method that was actually attempted first. This method has a different caveat: it switches to tab 0 when we have to stay on, for example, 1st tab and it happens when we come back from another screen open on top of the screen with tabs.
What's wrong this time? The stream builder re-emits last event (BehaviourSubject
based stream) and this way _currentTabIndex
is set to 0, while we need it to keep a current value. The solution is to "remember" the last event and recognize it just re-emitted. This may not solve all similar issues, but at least gives a clue.
A piece of code to illustrate the solution:
class HomeScreenState extends State<HomeScreen> {
int _currentTabIndex = 0;
AsyncSnapshot<UIState> lastSnapshot;
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: Drawer(
elevation: 0.0,
child: DrawerScreen(),
),
body: StreamBuilder(
stream: _drawerStream,
builder: (context, AsyncSnapshot<UIState> snapshot) {
if (_currentTabIndex != 0 && lastSnapshot != snapshot) {
SchedulerBinding.instance.addPostFrameCallback((_) =>
setState(() => _currentTabIndex = nextTab));
}
lastSnapshot = snapshot;
return CupertinoTabScaffold(
tabBar: CupertinoTabBar(
onTap: (index) {
_currentTabIndex = index;
},
currentIndex: _currentTabIndex,
backgroundColor: Colors.white,
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
title: Text('Main'),
icon: Icon(IconData(0xe800), size: 20),
),
BottomNavigationBarItem(
title: Text('Goodies'),
icon: Icon(IconData(0xe84b), size: 20),
),
],
),
tabBuilder: (BuildContext context, int index) {
return CupertinoTabView(
builder: (BuildContext context) {
switch (index) {
case 0: return MainScreen();
case 1: return GoodiesScreen();
}
},
);
},
),
);
}
}
Upvotes: 1