I have a 2 tab screen where I want to dynamically rebuild the content depending on user's interactions. On the first tab there are multiple states which I try to handle by setting a current step name using model and provider. For the second screen after pressing a button I get the print message in a console but the content of CupertinoTabView remains unchanged.
Minimum runnable code snippet:
main.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:my_app/screens/login.dart';
import 'package:my_app/screens/tab_bar.dart';
import 'package:my_app/models/model.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
return runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => Model(),
),
],
child: CupertinoApp(
theme: const CupertinoThemeData(
brightness: Brightness.light,
scaffoldBackgroundColor: CupertinoColors.white,
),
initialRoute: '/',
routes: {
'/': (context) => LoginScreen(),
'/tab_bar': (context) => TabBarScreen(),
//'/add_item': (context) => AddItemScreen(),
},
),
);
}
}
login.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:my_app/models/model.dart';
class LoginScreen extends StatelessWidget {
final model = Model();
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('app',),
),
child: Container(
alignment: FractionalOffset.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
child: Text('next'),
onPressed: (){
model.setStep('step1');
Navigator.pushNamed(context, '/tab_bar');
},
style: ElevatedButton.styleFrom(
primary: CupertinoColors.white,
side: BorderSide(color: Colors.blue, width: 2.0)
),
),
]
),
),
);
}
}
tab_bar.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:my_app/models/model.dart';
class TabBarScreen extends StatefulWidget {
#override
State createState() => TabBarScreenState();
}
class TabBarScreenState extends State<TabBarScreen> {
final model = Model();
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
print(model.getStep);
return Consumer<Model>(
builder: (context, model, _) => CupertinoTabScaffold(
tabBar: CupertinoTabBar(
backgroundColor: CupertinoColors.white,
inactiveColor: Colors.blue,
activeColor: Colors.blueAccent,
border: const Border(
top: BorderSide(
color: CupertinoColors.activeBlue,
width: 2.0,
),
),
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.favorite_outline_outlined),
),
BottomNavigationBarItem(
icon: Icon(Icons.more_vert_sharp),
),
],
),
tabBuilder: (context, index) {
late final CupertinoTabView returnValue;
switch (index) {
case 0:
if (model.getStep == 'step1') {
print('step1');
returnValue = CupertinoTabView(builder: (context) {
return CupertinoPageScaffold(
child: SafeArea(
child: GestureDetector(
onTap: (){ },
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
margin: const EdgeInsets.only(bottom: 15.0),
child: FloatingActionButton(
onPressed: () { model.setStep('step2'); setState(() {
}); },
tooltip: 'step2',
child: Icon(Icons.add),
backgroundColor: CupertinoColors.white,
foregroundColor: CupertinoColors.black,
),
),
],
),
],
),
),
),
);
});
}
else if (model.getStep == 'step2') {
print('step2');
returnValue = CupertinoTabView(builder: (context) {
return CupertinoPageScaffold(
child: SafeArea(
child: Column(
children: <Widget> [
Text('step2'),
],
),
),
);
});
}
else {
returnValue = CupertinoTabView(builder: (context) {
return Container();
});
}
break;
case 1:
returnValue = CupertinoTabView(builder: (context) {
return CupertinoPageScaffold(
child: Text("Tab2"),
);
});
break;
}
return returnValue;
},
),
);
}
}
model.dart
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class Model extends ChangeNotifier {
static String currentStep = 'login';
// login
// step1 - step1
// step2 - step2
String get getStep {
return currentStep;
}
void setStep(String step) {
currentStep = step;
notifyListeners();
}
}
I want the tab to rebuild on pressing a button from step1 to show the step2 content. In a console I can see the print of 'step2' when pressing, but the actual tab remains unchanged.
Appreciate your help
Since nobody have answered I figured it out on my own.
The resolution is to use Navigator like this:
onPressed: () {
Navigator.of(context).push(
CupertinoPageRoute<void>(
builder: (BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('Page 2 of tab'),
),
child: Center(
child: CupertinoButton(
child: const Text('Back'),
onPressed: () { Navigator.of(context).pop(); },
),
),
);
},
),
);
},
and therefore you won't need 'else if' conditioning.
Related
i'm trying to implement provider in my flutter app but getting a little stuck.
It's basically a list of tasks. You should be able to double tap an existing task and edit the text. Below the task text is a counter which shows how long the task text is but it never updates when I type. Any ideas why?
task.dart
class Task {
String taskText;
bool completed;
String id = UniqueKey().toString();
Task({
this.taskText = '',
this.completed = false,
});
void toggle() {
completed = !completed;
}
}
task_data.dart
import 'dart:collection';
import 'package:flutter/foundation.dart';
import 'package:task_management/model/task.dart';
class TaskData with ChangeNotifier {
List<Task> _tasks = [];
UnmodifiableListView<Task> get tasks => UnmodifiableListView(_tasks);
void addTask(Task task) {
int index = _tasks.indexWhere((element) => element.id == task.id);
if (index == -1) {
_tasks.add(task);
} else {
_tasks[index] = task;
}
notifyListeners();
}
void toggleTask(Task task) {
task.toggle();
notifyListeners();
}
void removeTask(Task task) {
_tasks.remove(task);
notifyListeners();
}
}
main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'model/task_data.dart';
import 'screens/home.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => TaskData(),
child: MaterialApp(
title: 'Provider Demo',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: Home(),
),
);
}
}
home.dart
import 'package:flutter/material.dart';
import 'package:task_management/screens/task_list.dart';
import 'task_form.dart';
class Home extends StatelessWidget {
// create the appbar
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('GeeksforGeeks'),
),
body: Container(
padding: EdgeInsets.all(20),
child: TaskList(),
),
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.add,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TaskForm(
taskIndex: -1,
)));
},
),
);
}
}
task_list.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:task_management/model/task_data.dart';
import 'task_form.dart';
class TaskList extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Consumer<TaskData>(builder: (context, data, child) {
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: data.tasks.length,
itemBuilder: (context, index) {
final task = data.tasks[index];
// gesture detection
return GestureDetector(
onLongPress: () => data.removeTask(task),
onDoubleTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TaskForm(
taskIndex: index,
)));
},
child: Container(
margin: EdgeInsets.only(bottom: 10),
padding: EdgeInsets.fromLTRB(12, 5, 8, 5),
width: double.infinity,
decoration: BoxDecoration(color: Colors.black12, borderRadius: BorderRadius.circular(8)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// text field
Text(
task.taskText,
style: TextStyle(decoration: task.completed ? TextDecoration.lineThrough : null, fontSize: 16, fontWeight: FontWeight.bold),
),
// switch case
Switch(
value: task.completed,
onChanged: (c) => data.toggleTask(task),
),
],
),
),
);
},
);
});
}
}
task_form.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:task_management/model/task.dart';
import 'package:task_management/model/task_data.dart';
class TaskForm extends StatelessWidget {
final int taskIndex;
TaskForm({required this.taskIndex});
#override
Widget build(BuildContext context) {
TaskData taskProvider = Provider.of<TaskData>(context);
Task task = taskIndex != -1 ? taskProvider.tasks[taskIndex] : Task();
return Scaffold(
appBar: AppBar(
title: Text('Task Form'),
),
body: Container(
padding: EdgeInsets.all(18),
child: Column(
children: [
TextFormField(
initialValue: task.taskText,
onChanged: (c) => task.taskText = c,
),
Text(task.taskText.length.toString()),
// add button
ElevatedButton(
child: Text(
'Submit',
),
// assign action
onPressed: () {
Provider.of<TaskData>(context, listen: false).addTask(task);
Navigator.pop(context);
},
)
],
),
),
);
}
}
This happened as the Task object not notifying the changes,
Try
TextFormField(
initialValue: task.taskText,
onChanged: (c) {
task.taskText = c,
Provider.of<TaskData>(context, listen: false).notifyListeners();
}
),
I am new to Flutter and I am using Provider in my Flutter App and my main.dart file looks like this :
import 'package:flutter/material.dart';
import 'package:provider_practice/screens/first_screen.dart';
import 'package:provider_practice/screens/second_screen.dart';
import 'package:provider/provider.dart';
import 'package:provider_practice/counter.dart';
void main() {
runApp(MaterialApp(
home: ChangeNotifierProvider<Counter>(
create: (context) => Counter(),
child: FirstScreen(),
),
routes: {
"/first" : (context) => FirstScreen(),
"/second" : (context) => SecondScreen(),
},
));
}
My code works fine on FirstScreen() but when I navigate to SecondScreen() (by using Navigator.pushNamed()), I get the following error :
The following ProviderNotFoundException was thrown building SecondScreen(dirty):
Error: Could not find the correct Provider<Counter> above this SecondScreen Widget
Is there anyway to fix this ? I am using Provider version ^5.0.0
first_screen.dart :-
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:provider_practice/counter.dart';
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
final counter = Provider.of<Counter>(context , listen: false);
return Scaffold(
appBar: AppBar(
title: Text("First Screen"),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Consumer<Counter>(
builder: (_ , counter , __) => Text("You pressed the button
${counter.firstCounter} times.")
),
SizedBox(height: 20),
RaisedButton(
onPressed: counter.firstIncrement,
child: Text("Click Me"),
),
SizedBox(height: 20),
RaisedButton(
onPressed: () {
Navigator.pushNamed(context, "/second");
},
child: Text("Go to Second"),
),
],
),
),
),
);
}
}
second_screen.dart :-
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:provider_practice/counter.dart';
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
final counter = Provider.of<Counter>(context , listen: false);
return Scaffold(
appBar: AppBar(
title: Text("Second Screen"),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Consumer<Counter>(
builder: (_ , counter , __) => Text("You pressed the button
${counter.secondCounter} times.")
),
SizedBox(height: 20),
RaisedButton(
onPressed: counter.secondIncrement,
child: Text("Click Me"),
),
SizedBox(height: 20),
RaisedButton(
onPressed: () {
//Navigator.maybePop(context);
Navigator.pushNamed(context, "/first");
//Navigator.pop(context);
},
child: Text("Go to First"),
),
],
),
),
),
);
}
}
counter.dart :-
import 'package:flutter/foundation.dart';
class Counter with ChangeNotifier {
int firstCounter = 0;
int secondCounter = 0;
void firstIncrement() {
firstCounter++;
notifyListeners();
}
void secondIncrement() {
secondCounter++;
notifyListeners();
}
}
Without seeing reproducable snippets of your code we cant help,
anyway you can return a multiprovider before material app and add your provider here
....
return MultiProvider(
providers: [
ChangeNotifierProvider<Counter>(
create: (context) => Counter()),
]
child:MaterialApp
You can try this way.
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => AriticleProvider()),
ChangeNotifierProvider(create: (_) => FavoriteProvider()),
],
child: MyApp(),
),
);
I have created a simple app using InheritedWidget, just a counter app...
I have just four files:
main.dart.
CommonScreenProvider.dart.
first_screen.dart.
second_screen.dart.
the problem here when I am trying to use the counter function in in the second_screen and go back to the first_screen I can not find any updates till I use the counter but while I use counter in first screen I found the updated value in the second screen without problem, I think there's missing a refresh function or something?
Here's the code implementation...
CommonScreenProvider
import 'package:flutter/material.dart';
class CommonScreenProvider extends InheritedWidget {
num counter = 0;
Widget child;
CommonScreenProvider({#required this.child});
#override
bool updateShouldNotify(covariant CommonScreenProvider oldWidget) {
return oldWidget.counter != counter;
}
static CommonScreenProvider of(BuildContext ctx) =>
ctx.dependOnInheritedWidgetOfExactType();
}
first_screen
import 'package:flutter/material.dart';
import 'package:statemanagementtest/second_screen.dart';
import 'commom_screen_provider.dart';
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var provider = CommonScreenProvider.of(ctx);
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.send_to_mobile),
onPressed: () {
Navigator.of(ctx).push(
MaterialPageRoute(
builder: (ctx) => SecondScreen(),
),
);
},
),
],
title: Text('My Counter App'),
),
body: Center(
child: StatefulBuilder(builder: (ctx, StateSetter setState) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.remove),
iconSize: 50,
onPressed: () {
setState(() {
provider.counter--;
});
},
),
Text(
'${provider.counter}',
style: Theme.of(ctx).textTheme.display1,
),
IconButton(
icon: Icon(Icons.add),
iconSize: 50,
onPressed: () {
setState(() {
provider.counter++;
});
},
),
],
);
}),
),
);
}
}
second_screen
import 'package:flutter/material.dart';
import 'commom_screen_provider.dart';
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var pSecond = CommonScreenProvider.of(ctx);
return Scaffold(
appBar: AppBar(
title: Text('My Counter App'),
),
body: Center(
child: StatefulBuilder(builder: (ctx, StateSetter setState) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.remove),
iconSize: 50,
onPressed: () {
setState(() {
pSecond.counter--;
});
},
),
Text(
'${pSecond.counter}',
style: Theme.of(ctx).textTheme.display1,
),
IconButton(
icon: Icon(Icons.add),
iconSize: 50,
onPressed: () {
setState(() {
pSecond.counter++;
});
},
),
],
);
}),
),
);
}
}
main.dart
import 'package:flutter/material.dart';
import 'package:statemanagementtest/commom_screen_provider.dart';
import 'package:statemanagementtest/first_screen.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
return CommonScreenProvider(
child: MaterialApp(
home: FirstScreen(),
),
);
}
}
You can copy paste run full code below
Quick fix is move StatefulBuilder up and await Navigator.of(ctx).push then call setState
code snippet
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var provider = CommonScreenProvider.of(ctx);
return StatefulBuilder(builder: (ctx, StateSetter setState) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.send_to_mobile),
onPressed: () async {
await Navigator.of(ctx).push(
MaterialPageRoute(
builder: (ctx) => SecondScreen(),
),
);
setState(() {});
working demo
full code
import 'package:flutter/material.dart';
class CommonScreenProvider extends InheritedWidget {
num counter = 0;
Widget child;
CommonScreenProvider({#required this.child});
#override
bool updateShouldNotify(covariant CommonScreenProvider oldWidget) {
return oldWidget.counter != counter;
}
static CommonScreenProvider of(BuildContext ctx) =>
ctx.dependOnInheritedWidgetOfExactType();
}
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var provider = CommonScreenProvider.of(ctx);
return StatefulBuilder(builder: (ctx, StateSetter setState) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.send_to_mobile),
onPressed: () async {
await Navigator.of(ctx).push(
MaterialPageRoute(
builder: (ctx) => SecondScreen(),
),
);
setState(() {});
},
),
],
title: Text('My Counter App'),
),
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.remove),
iconSize: 50,
onPressed: () {
setState(() {
provider.counter--;
});
},
),
Text(
'${provider.counter}',
style: Theme.of(ctx).textTheme.display1,
),
IconButton(
icon: Icon(Icons.add),
iconSize: 50,
onPressed: () {
setState(() {
provider.counter++;
});
},
),
],
)),
);
});
}
}
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var pSecond = CommonScreenProvider.of(ctx);
return Scaffold(
appBar: AppBar(
title: Text('My Counter App'),
),
body: Center(
child: StatefulBuilder(builder: (ctx, StateSetter setState) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.remove),
iconSize: 50,
onPressed: () {
setState(() {
pSecond.counter--;
});
},
),
Text(
'${pSecond.counter}',
style: Theme.of(ctx).textTheme.display1,
),
IconButton(
icon: Icon(Icons.add),
iconSize: 50,
onPressed: () {
setState(() {
pSecond.counter++;
});
},
),
],
);
}),
),
);
}
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
return CommonScreenProvider(
child: MaterialApp(
home: FirstScreen(),
),
);
}
}
I have following route in my app:
Main.dart ---> SplashScreen.dart ---> DetailsPage.dart
Main.dart
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => FontSizeHandler()),
],
child: MyApp(),
),
);
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SplashScreen(),
);
}
}
From SplashScreen.dart I move to DetailsPage.dart using Navigator.pushAndRemoveUntil i.e
Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context) => DetailsPage()), (route) => false);
Now in Details page on App Bar there is icon and on press of which I want to change the font using FontSizeHandler
DetailsPage.dart
class DetailsPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
icon: Icon(Icons.arrow_upward),
onPressed: () {
context.read<FontSizeHandler>().increaseFont();
},
),
IconButton(
onPressed: () {
context.read<FontSizeHandler>().decreaseFont();
},
icon: Icon(Icons.arrow_downward),
),
],
title: Text(
"DetailsPage",
style: GoogleFonts.roboto(),
),
),
body: SafeArea(
child: SingleChildScrollView(
child: Card(
child: Container(
padding: EdgeInsets.fromLTRB(5, 5, 5, 15),
child: AutoSizeText(
"MyTexts",
textAlign: TextAlign.justify,
style: GoogleFonts.openSans(
fontSize:
context.watch<FontSizeHandler>().fontSize.toDouble(),
),
),
),
),
),
),
);
}
}
So the problem here is I am getting this error message
Could not find the correct Provider This likely
happens because you used a BuildContext that does not include the
provider
Is this error is due to I used Navigator.pushAndRemoveUntil?
Though I have ChangeNotifierProvider at top of hierarchy why is it throwing error?
How to solve this?
FontSizeHandler.dart
class FontSizeHandler with ChangeNotifier {
int fontSize = 15;
void increaseFont() {
fontSize = fontSize + 2;
notifyListeners();
}
void decreaseFont() {
fontSize = fontSize - 2;
notifyListeners();
}
}
Solved: The Problem Was With Importing Wrong ChangeNotifier class. Never Trust autoimport again
Updated Answer
For reference, the issue was caused by an erroneous import as below:
import 'file:///.../fontchangehandler.dart'; // import 'package:.../fontchangehandler.dart';
Original Answer
Unfortunately I was unable to reproduce the error that you are experiencing using the provided code. If you could provide the rest of the code from the DetailsPage class then that might help to further diagnose the error. I was able to get the example below working which hopefully you might find useful:
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<FontSizeHandler>(
create: (context) {
return FontSizeHandler();
},
),
],
child: MyApp(),
),
);
}
class FontSizeHandler extends ChangeNotifier {
int _fontSize = 15;
int get fontSize => _fontSize;
void increaseFont() {
_fontSize = _fontSize + 2;
notifyListeners();
}
void decreaseFont() {
_fontSize = _fontSize - 2;
notifyListeners();
}
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SplashScreen(),
);
}
}
class SplashScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
onPressed: () async {
await Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) {
return DetailsPage();
},
),
(route) => false,
);
},
child: Text('GO TO DETAILS'),
),
),
);
}
}
class DetailsPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
icon: Icon(Icons.arrow_upward),
onPressed: () {
context.read<FontSizeHandler>().increaseFont();
},
),
IconButton(
onPressed: () {
context.read<FontSizeHandler>().decreaseFont();
},
icon: Icon(Icons.arrow_downward),
),
],
title: Text(
"DetailsPage",
style: GoogleFonts.roboto(),
),
),
body: SafeArea(
child: SingleChildScrollView(
child: Card(
child: Container(
padding: EdgeInsets.fromLTRB(5, 5, 5, 15),
child: AutoSizeText(
"MyTexts",
textAlign: TextAlign.justify,
style: GoogleFonts.openSans(
fontSize: context.watch<FontSizeHandler>().fontSize.toDouble(),
),
),
),
),
),
),
);
}
}
In my app, the FutureBuilder works fine when I use BottomNavigationBarItem (cf Home widget).
However, when I user Navigator.push and Navigator.pop, the FutureBuilder is not triggered.
I can't understand why, any help would be highly appreciated.
Bellow my code.
Home widget
import 'package:com.pro.cocotal.online/models/product.dart';
import 'package:com.pro.cocotal.online/models/user.dart';
import 'package:com.pro.cocotal.online/screens/home/products/productListScreen.dart';
import 'package:com.pro.cocotal.online/screens/home/shopSettings/shopSettings.dart';
import 'package:flutter/material.dart';
class Home extends StatefulWidget {
final User user;
final List<Product> products;
Home(this.user, this.products);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _selectedIndex = 0;
List<Widget> _widgetOptions;
#override
void initState(){
_widgetOptions = <Widget>[
ProductListScreen(widget.user, widget.products),
ShopSettings(widget.user),
];
}
//navigue dans les menus
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body:Center(
child: Scaffold(
body:_widgetOptions.elementAt(_selectedIndex),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
title: Text(''),
icon: Icon(Icons.home, color: Colors.blueAccent, size: 35),
),
BottomNavigationBarItem(
title: Text(''),
icon: Icon(Icons.settings, color: Colors.blueAccent, size: 35)
)
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
),
)
);
}
}
ProductListScreen class
import 'package:com.pro.cocotal.online/models/product.dart';
import 'package:com.pro.cocotal.online/models/user.dart';
import 'package:com.pro.cocotal.online/screens/home/products/addProductScreen.dart';
import 'package:com.pro.cocotal.online/screens/home/products/productScreen.dart';
import 'package:com.pro.cocotal.online/services/productService.dart';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
class ProductListScreen extends StatefulWidget {
final List<Product> products;
final User user;
ProductListScreen(this.user, this.products);
#override
_ProductsState createState() => _ProductsState();
}
class _ProductsState extends State<ProductListScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Tienda " + widget.user.storeName),
elevation: 0,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
backgroundColor: Colors.blue,
expandedHeight: 130,
flexibleSpace: FlexibleSpaceBar(
background: Image.network(
"https://cocotal.online/wp-content/uploads/revslider/cropped-slider-41.jpg",
fit: BoxFit.cover,
),
),
),
FutureBuilder(
future: ProductService().getProducts(widget.user),
builder: (context, productSnaps){
List<Product> products = productSnaps.data;
if (productSnaps.connectionState != ConnectionState.done) {
return SliverFixedExtentList(
itemExtent: 1,
delegate: SliverChildBuilderDelegate(
(context, i) {
return SpinKitRotatingCircle(
color: Colors.white,
size: 50.0,
);
},
childCount: 1,
),
);
}
if (productSnaps.hasData == null) {
return SliverFixedExtentList(
itemExtent: 0,
delegate: SliverChildBuilderDelegate(
(context, i) {
return ListTile(
title: Text("null"),
trailing: Icon(Icons.delete),
onTap: () {
},
);
},
childCount: 1,
),
);
}
return SliverFixedExtentList(
itemExtent: 50,
delegate: SliverChildBuilderDelegate(
(context, i) {
return ListTile(
title: Text(products[i].name),
trailing: Icon(Icons.delete),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ProductScreen(products[i])));
},
);
},
childCount: products.length,
),
);
},
),
],
),
),
RaisedButton.icon(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => AddProduct()));
},
icon: Icon(Icons.add_circle),
label: Text('Add a product')
),
],
)
);
}
}
ProductScreen class
import 'package:com.pro.cocotal.online/models/product.dart';
import 'package:flutter/material.dart';
class ProductScreen extends StatefulWidget {
final Product product;
const ProductScreen(this.product);
#override
_ProductScreenState createState() => _ProductScreenState();
}
class _ProductScreenState extends State<ProductScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.product.name),
leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: ()async{
Navigator.pop(context);
}),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Row(
children: <Widget>[
Text("Nom : " + widget.product.name),
],
),
Row(
children: <Widget>[
Text("Description : " + widget.product.description),
],
),
Row(
children: <Widget>[
Text("Prix : " + widget.product.price),
],
),
],
),
);
}
}