How to refresh Widget in CupertinoTabScaffold tabBuilder Flutter? - flutter

I have a tabBuilder with switch case, I have a tab that needs to be refreshed after authorization or logout. I have a token variable which is assigned a value after authorization. I need to update the widget every time my variable is assigned a value, how can i make it? I also have a way to update the tab every time you go to it, but it will not work here
#override
Widget build(BuildContext context) {
setState(() {
Constants.USER_TOKEN; // my token variable
});
return CupertinoTabScaffold(
controller: _controller,
key: myKey,
backgroundColor: Colors.black87,
tabBar: CupertinoTabBar(
iconSize: 30,
currentIndex: currentIndex,
onTap: onItemTapped,
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home, size: 25)),
BottomNavigationBarItem(icon: Icon(Icons.store, size: 25,)),
BottomNavigationBarItem(icon: Icon(Icons.shopping_bag, size: 25)),
BottomNavigationBarItem(icon: Icon(Icons.person, size: 25)),
],
),
tabBuilder: (BuildContext context, int index) {
print(currentIndex);
switch (index) {
case 0:
// The page that should be updated when the variable changes
return
CupertinoTabView(
builder: (BuildContext context) {
return const CupertinoPageScaffold(
resizeToAvoidBottomInset: false,
child: HomePage(),
);
},
);
case 1:
return CupertinoTabView(
builder: (BuildContext context) {
return const CupertinoPageScaffold(
resizeToAvoidBottomInset: false,
child: CatalogPage(),
);
},
);
case 2:
return currentIndex == 2 ? // my always refresh method
CupertinoTabView(
builder: (BuildContext context) {
return const CupertinoPageScaffold(
resizeToAvoidBottomInset: false,
child: ShoppingBag(),
);
},
) : Container();
case 3:
return CupertinoTabView(
builder: (BuildContext context) {
return const CupertinoPageScaffold(
resizeToAvoidBottomInset: false,
child: UserProfileScaffold(),
);
},
);
default:
return Container();
}
});
}

Related

How to navigate from a different page on a different tab using CupertinoTabBar?

I have 4 tabs and for each tab I have a page, I use CupertinoTabScaffold to build my tabs:
Widget build(BuildContext context) {
return CupertinoTabScaffold(
controller: controller,
backgroundColor: Colors.black87,
tabBar: CupertinoTabBar(
iconSize: 30,
currentIndex: currentIndex,
onTap: (index) => setState(() => currentIndex = index),
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home, size: 25)),
BottomNavigationBarItem(icon: Icon(Icons.store, size: 25,)),
BottomNavigationBarItem(icon: Icon(Icons.shopping_bag, size: 25)),
BottomNavigationBarItem(icon: Icon(Icons.person, size: 25)),
],
),
tabBuilder: (BuildContext context, int index) {
switch (index) {
case 0:
return CupertinoTabView(
navigatorKey: navigatorKeyList[index],
builder: (BuildContext context) {
return CupertinoPageScaffold(
resizeToAvoidBottomInset: false,
child: HomePage(),
);
},
);
case 1:
return CupertinoTabView(
navigatorKey: navigatorKeyList[index],
builder: (BuildContext context) {
return CupertinoPageScaffold(
resizeToAvoidBottomInset: false,
child: CatalogPage(),
);
},
);
case 2:
return CupertinoTabView(
navigatorKey: navigatorKeyList[index],
builder: (BuildContext context) {
return CupertinoPageScaffold(
resizeToAvoidBottomInset: false,
child: ShoppingBag(),
);
},
);
case 3:
return CupertinoTabView(
navigatorKey: navigatorKeyList[index],
builder: (BuildContext context) {
return CupertinoPageScaffold(
resizeToAvoidBottomInset: false,
child: UserProfileScaffold(),
);
},
);
default:
return CupertinoTabView(
builder: (BuildContext context) {
return CupertinoPageScaffold(
resizeToAvoidBottomInset: false,
child: HomePage(),
);
},
);
}
});
}
I want to switch between tabs when I use Navigator.push, not just push to the page, like in material BottomNavigationBar.
Edited
Here is an example of what my Navigator.push should look like:
ElevatedButton(onPressed: () async {
SharedPreferences pref = await SharedPreferences.getInstance();
await pref.clear();
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => CupertinoBottomNavBarPage(tab: 0)),
(route) => false);
},
child: const Text('logout'))

Flutter change background color using streambuilder

I'm new in Flutter and bloc architecture and I try some things.
Here I'll just try to set my background color, and it works with this code
final ColorBloc _bloc = ColorBloc();
#override
Widget build(BuildContext context) {
return StreamBuilder<Response<ColorResponse>>(
stream: _bloc.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
switch (snapshot.data.status) {
case Status.LOADING:
return Loading(loadingMessage: snapshot.data.message);
break;
case Status.COMPLETED:
return Scaffold(
appBar: AppBar(
title: Text('First Route clicked'),
),
backgroundColor: snapshot.data.data.color,
body: new Center(
child: new InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Act2()),
);
}, // Handle your callback
child: Ink(height: 100, width: 100, color: Colors.blue),
)),
floatingActionButton: FloatingActionButton(
onPressed: () {
_bloc.changeColor(Colors.yellow);
},
child: Icon(Icons.navigation),
backgroundColor: Colors.green,
));
break;
case Status.ERROR:
return Error(
errorMessage: snapshot.data.message,
//onRetryPressed: () => _bloc.fetchCategories(),
);
break;
}
}
);
}
}
But I need to rebuild all my page, can I just set the background color with the streamBuilder answer ?
EDIT: Should I use session to store my final color ?

How can i disable a particular tab in CupertinoTabView, to be able to click?

I want when the user is not logged in the tabs will be disabled except the tab of "Mon Compte" and "Annonces" will be activated.
Is there a way to turn off a particular tab in the CupertinoTabView? so that it cannot be clicked unless the user is logged in? or how can I change index if the user is not connected Any help is welcome, thank you!
class BottomMenu extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _BottomMenuState();
}
}
class _BottomMenuState extends State<BottomMenu> {
static int currentTab = 3; // to keep track of active tab index
#override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarBrightness: Brightness.light,
systemNavigationBarColor: Colors.transparent,
systemNavigationBarIconBrightness: Brightness.light,
),
);
return CupertinoTabScaffold(
tabBar: CupertinoTabBar(
currentIndex: currentTab ,
activeColor: Theme.of(context).primaryColor,
backgroundColor: Theme.of(context).backgroundColor,
inactiveColor: Theme.of(context).disabledColor,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.search),
title: Text(
"Matching"
),
),
BottomNavigationBarItem(
icon: Icon(Icons.dashboard),
title:
Text(
"Annonces"
),
),
BottomNavigationBarItem(
icon: Icon(MenuIcon.favorite__1_),
title:
Text("Favoris"),
),
BottomNavigationBarItem(
icon: Icon(MenuIcon.user__1_),
title: Text(
"Mon Compte"
),
),
],
),
tabBuilder: (context, index) {
switch (index) {
case 0:
return CupertinoTabView(builder: (context) {
return CupertinoPageScaffold(
child: Matching(),
);
}
);
case 1:
return CupertinoTabView(builder: (context) {
return CupertinoPageScaffold(
child: Offers(),
);
});
case 2:
return CupertinoTabView(builder: (context) {
return CupertinoPageScaffold(
child: Favorites(),
);
});
default: return CupertinoTabView(
builder: (context) {
return CupertinoPageScaffold(
child: Login(),
);
});
}
},
);
}
}

What is the use of `rootNavigator` in Navigator.of(context, rootNavigator: true).push();

What's the difference between
Navigator.of(context).pushNamed("/route");
and
Navigator.of(context, rootNavigator: true).pushNamed("/route");
More importantly, what's the use of setting rootNavigator: true on Navigator class, I read docs but they aren't quite clear. Can anyone explain the difference properly?
You can copy paste run full code below
There is a root Navigator above tab navigation
This demo shows open(Navigator.push) a full screen dialog (fullscreenDialog: true) with rootNavigator true/false
picture
rootNavigator = true , fullscreenDialog take all screen and above tab
rootNavigator = false, fullscreenDialog take tab size and inside tab, you can switch between Home and Support tab and see fullscreenDialog is still there
working demo
code snippet
Center(
child: CupertinoButton(
child: const Text(
'Push rootNavigator true',
),
onPressed: () {
Navigator.of(context, rootNavigator: true).push(
CupertinoPageRoute<bool>(
fullscreenDialog: true,
builder: (BuildContext context) => Tab3Dialog(),
),
);
},
),
),
Center(
child: CupertinoButton(
child: const Text(
'Push rootNavigator false',
),
onPressed: () {
Navigator.of(context, rootNavigator: false).push(
CupertinoPageRoute<bool>(
fullscreenDialog: true,
builder: (BuildContext context) => Tab3Dialog(),
),
);
},
),
),
full code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: PawzHome(),
);
}
}
class PawzHome extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoTabScaffold(
tabBar: CupertinoTabBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.home),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.conversation_bubble),
title: Text('Support'),
),
],
),
tabBuilder: (BuildContext context, int index) {
switch (index) {
case 0:
return CupertinoTabView(
builder: (BuildContext context) {
return CupertinoDemoTab1();
},
defaultTitle: 'Colors',
);
break;
case 1:
return CupertinoTabView(
builder: (BuildContext context) => CupertinoDemoTab2(),
defaultTitle: 'Support Chat',
);
break;
}
return null;
},
);
}
}
class CupertinoDemoTab1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: CustomScrollView(
slivers: <Widget>[
CupertinoSliverNavigationBar(),
SliverList(
delegate: SliverChildListDelegate([Tab1RowItem()]),
),
],
),
);
}
}
class Tab1RowItem extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).push(CupertinoPageRoute<void>(
title: "Click me",
builder: (BuildContext context) => Tab1ItemPage(),
));
},
child: Padding(padding: EdgeInsets.all(10.0), child: Text("Click me")),
);
}
}
class Tab1ItemPage extends StatelessWidget {
#override
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(),
child: Container(
child: Column(
children: <Widget>[
SizedBox(height: 100,),
Center(
child: CupertinoButton(
child: const Text(
'Push rootNavigator true',
),
onPressed: () {
Navigator.of(context, rootNavigator: true).push(
CupertinoPageRoute<bool>(
fullscreenDialog: true,
builder: (BuildContext context) => Tab3Dialog(),
),
);
},
),
),
Center(
child: CupertinoButton(
child: const Text(
'Push rootNavigator false',
),
onPressed: () {
Navigator.of(context, rootNavigator: false).push(
CupertinoPageRoute<bool>(
fullscreenDialog: true,
builder: (BuildContext context) => Tab3Dialog(),
),
);
},
),
),
],
),
));
}
}
class CupertinoDemoTab2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(),
child: Container(
child: Center(
child: Text("Tab 2"),
),
));
}
}
class Tab3Dialog extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
leading: CupertinoButton(
onPressed: () {
Navigator.of(context).pop(false);
},
child: Text("Ok"),
),
),
child: Center(
child: CupertinoButton(
color: CupertinoColors.activeBlue,
child: const Text('Sign in'),
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
}
If your app has nested navigators this parameter comes in handy when you want to call the root navigator not it's nested navigators ... please consider the image bellow ... in this example we are inside the page 2 and we want the page 3 to be the rootNavigator's child (because for example we want to ignore the bottomNavigationBar that is in MainPage)... in this example if you don't set the rootNavigator = true and you push the page 3 it will be the nestedNavigator's child (So the BottomNavigationBar of the MainPage's will be still visible).

Flutter: keep widget alive (streambuilder)

I have a flutter app with a Pageview (and at the bottom a cupertinotabbar). Everything 'works'. But when I switch pages, the streambuilders 'glitch'. (There's one on the first page and on the second page) (see video).
I think the problem is that flutter 'destroys' the streambuilders and then reloads them.
I tried putting keepClientAlive on the statefull widget, but didn't work.
Is there a possibility to keep the streambuilder alive?
This is my code:
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async => false,
child: Scaffold(
body: PageView(
children: <Widget>[
Discover(currentUser: currentUser),
Friends(currentUser: currentUser),
Find(),
],
controller: pageController,
onPageChanged: onPageChanged,
physics: NeverScrollableScrollPhysics(),
),
bottomNavigationBar: CupertinoTabBar(
backgroundColor: Colors.black,
currentIndex: pageIndex,
onTap: onTap,
activeColor: Colors.green,
items: [
BottomNavigationBarItem(icon: Icon(FontAwesomeIcons.search)),
BottomNavigationBarItem(icon: Icon(FontAwesomeIcons.users)),
BottomNavigationBarItem(icon: Icon(FontAwesomeIcons.biking)),
],
),
),
);
}
My streambuilder class
class BookList extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('books').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError)
return new Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting: return new Text('Loading...');
default:
return new ListView(
children: snapshot.data.documents.map((DocumentSnapshot document) {
return new ListTile(
title: new Text(document['title']),
subtitle: new Text(document['author']),
);
}).toList(),
);
}
},
);
}
}
https://www.youtube.com/watch?v=y2yKhqvkT_A&feature=youtu.be
Thanks!