Related
I have an issue regarding the routing of the flutter for the web. For specific reasons in my project, I have multiple material apps. So the platform that I'm building is a material app, let's name it 'Parent'. In this material app at some point lower in the widget tree I have a child that is also a material app let's name it 'Child'. When the user arrives at the point in the Parent tree where Child is rendered, it looks like the routing of Parent is replaced with the actual routing of Child. Is there any way to prevent this from happening?
Since I can't share the actual code I've recreated a minimal example:
import 'package:flutter/material.dart';
void main() {
runApp(ParentApp());
}
class ParentApp extends StatefulWidget {
#override
_ParentAppState createState() => _ParentAppState();
}
class _ParentAppState extends State<ParentApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Parent',
initialRoute: '/parent-home',
routes: {
'/parent-home': (context) => ParentHome(),
'/parent-second': (context) => ParentSecondRoute(),
},
);
}
}
class ParentHome extends StatefulWidget {
#override
_ParentHomeState createState() => _ParentHomeState();
}
class _ParentHomeState extends State<ParentHome> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
body: Container(
child: Center(
child: RaisedButton(
child: Text('Go to second route'),
onPressed: () => Navigator.pushNamed(
context,
'/parent-second',
),
),
),
),
);
}
}
class ParentSecondRoute extends StatefulWidget {
#override
_ParentSecondRouteState createState() => _ParentSecondRouteState();
}
class _ParentSecondRouteState extends State<ParentSecondRoute> {
bool isChildRendered;
#override
void initState() {
isChildRendered = false;
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Flexible(
child: isChildRendered
? ChildApp()
: Container(
color: Colors.green,
child: Center(
child: RaisedButton(
child: Text('Go to home'),
onPressed: () => Navigator.of(context).pop(),
),
),
),
),
Flexible(
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Checkbox(
value: isChildRendered,
onChanged: (value) => setState(() {
isChildRendered = value;
}),
),
SizedBox(width: 5),
Text('Is child rendered?'),
],
),
),
)
],
),
);
}
}
class ChildApp extends StatefulWidget {
#override
_ChildAppState createState() => _ChildAppState();
}
class _ChildAppState extends State<ChildApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Child',
initialRoute: '/child-route-i-don\'t-want-to-see',
routes: {
'/child-route-i-don\'t-want-to-see': (context) => Container(
color: Colors.brown,
),
},
);
}
}
Solution with ModalRoute Class
You can solve it this way, by using the ModalRoute Class and passing the current route name defined in its settings as parameter to the Child:
ChildApp(ModalRoute.of(context).settings.name)
class ChildApp extends StatefulWidget {
final String route;
const ChildApp(this.route);
#override
_ChildAppState createState() => _ChildAppState();
}
class _ChildAppState extends State<ChildApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Child',
initialRoute: widget.route,
routes: {
widget.route: (context) => Container(
color: Colors.brown,
),
},
);
}
}
name → String?
The name of the route (e.g., "/settings"). [...]
Full example below:
import 'package:flutter/material.dart';
void main() {
runApp(ParentApp());
}
class ParentApp extends StatefulWidget {
#override
_ParentAppState createState() => _ParentAppState();
}
class _ParentAppState extends State<ParentApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Parent',
initialRoute: '/parent-home',
routes: {
'/parent-home': (context) => ParentHome(),
'/parent-second': (context) => ParentSecondRoute(),
},
);
}
}
class ParentHome extends StatefulWidget {
#override
_ParentHomeState createState() => _ParentHomeState();
}
class _ParentHomeState extends State<ParentHome> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
body: Container(
child: Center(
child: RaisedButton(
child: Text('Go to second route'),
onPressed: () => Navigator.pushNamed(
context,
'/parent-second',
),
),
),
),
);
}
}
class ParentSecondRoute extends StatefulWidget {
#override
_ParentSecondRouteState createState() => _ParentSecondRouteState();
}
class _ParentSecondRouteState extends State<ParentSecondRoute> {
bool isChildRendered;
#override
void initState() {
isChildRendered = false;
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Flexible(
child: isChildRendered
? ChildApp(ModalRoute.of(context).settings.name) // this line
: Container(
color: Colors.green,
child: Center(
child: RaisedButton(
child: Text('Go to home'),
onPressed: () => Navigator.of(context).pop(),
),
),
),
),
Flexible(
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Checkbox(
value: isChildRendered,
onChanged: (value) => setState(() {
isChildRendered = value;
}),
),
SizedBox(width: 5),
Text('Is child rendered?'),
],
),
),
)
],
),
);
}
}
class ChildApp extends StatefulWidget {
final String route;
const ChildApp(this.route); // and this one
#override
_ChildAppState createState() => _ChildAppState();
}
class _ChildAppState extends State<ChildApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Child',
initialRoute: widget.route,
routes: {
widget.route: (context) => Container(
color: Colors.brown,
),
},
);
}
}
Home
Second Route
The code below is as far as I have gotten so far. The search function works and when clicking on let's say "Google" you will come to a new page specific to "Google".
But I am unsure now how I can add specific text and images to the page. I for example don't want Facebook information to be put on a Google page. Is the smart to make a new List? What other options are there and how would I go about doing so?
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Search Example"),
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () {
showSearch(context: context, delegate: SearchItem());
}),
],
),
);
}
}
final List<String> myList = [
"google",
"IOS",
"Android",
"Linux",
"MacOS",
"Windows"
];
class SearchItem extends SearchDelegate<String> {
#override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = "";
})
];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
onPressed: () {
close(context, null);
});
}
#override
Widget buildResults(BuildContext context) {}
#override
Widget buildSuggestions(BuildContext context) {
final suggestionsList = query.isEmpty
? myList
: myList
.where((p) => p.toLowerCase().contains(query.toLowerCase()))
.toList();
return ListView.builder(
itemBuilder: (context, index) => ListTile(
onTap: () {
close(context, suggestionsList[index]);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailScreen(myList
.indexWhere((item) => item == suggestionsList[index]))));
},
title: Text(suggestionsList[index]),
),
itemCount: suggestionsList.length,
);
}
}
class DetailScreen extends StatelessWidget {
final int index;
DetailScreen(this.index);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("${myList[index]}"),),
body: Center(
child: Text(
"${myList[index]}",style: TextStyle(fontSize: 22),
),
));
}
}
Not Sure What you are trying to say, But If you Want to show more number of items on the Details Page, then in That Case you Can Create A class Which can Have all those items included in it, Which you want to show the in the details class.
Here is the working Code For the same, Please check
import 'package:flutter/material.dart';
//Below it the new Class you Will Need, or We can say a Modal You Need to have all your properties of the class,
//Which you wanna show in details page
class MyPlatforms {
String name;
String image;
MyPlatforms({this.image, this.name});
}
//A MyPlatforms list created using that modal
final List<MyPlatforms> myPlatformsList = [
MyPlatforms(image: "assets/images/google.png", name: "Google"),
MyPlatforms(image: "assets/images/ios.png", name: "IOS"),
MyPlatforms(image: "assets/images/linux.png", name: "Linux"),
MyPlatforms(image: "assets/images/android.png", name: "Android"),
MyPlatforms(image: "assets/images/mac.png", name: "MacOS"),
MyPlatforms(image: "assets/images/windows.png", name: "Windows"),
];
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Search Example"),
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () {
showSearch(context: context, delegate: SearchItem());
}),
],
),
);
}
}
final List<String> myList = [
"google",
"IOS",
"Android",
"Linux",
"MacOS",
"Windows"
];
class SearchItem extends SearchDelegate<String> {
#override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = "";
})
];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
onPressed: () {
close(context, null);
});
}
#override
Widget buildResults(BuildContext context) {}
#override
Widget buildSuggestions(BuildContext context) {
final suggestionsList = query.isEmpty
? myList
: myList
.where((p) => p.toLowerCase().contains(query.toLowerCase()))
.toList();
return ListView.builder(
itemBuilder: (context, index) => ListTile(
onTap: () {
close(context, suggestionsList[index]);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailScreen(
item: myPlatformsList[
index], //pass the index of the MyPlatforms list
)));
},
title: Text(suggestionsList[index]),
),
itemCount: suggestionsList.length,
);
}
}
class DetailScreen extends StatelessWidget {
final MyPlatforms
item; //Get the item, as a object of MyPlatforms class so the we can acess its all properties like image and name;
DetailScreen({this.item});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("${item.name}"),
),
body: Center(
child: new Column(
children: [
Text(
"${item.name}", //acessing the name property of the MyPlatforms class
style: TextStyle(fontSize: 22),
),
SizedBox(
height: 20.0,
),
Image.asset(
"${item.image}"), //acessing the image property of the MyPlatforms class
],
),
));
}
}
I have two tabs - Tab1 and Tab2. Tab1 has 3 pages - Tab1 Page1, Tab1 Page2, Tab1 Page3.
I want to be able to navigate from Tab2 to Tab1 Page2. I can switch the index using controller.index = 0 but am not sure how to navigate to to Page2 of this tab. What is a clean solution for this?
// main.dart
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Cupertino Tab Bar Demo',
theme: ThemeData(primarySwatch: Colors.blue, textTheme: TextTheme()),
home: SafeArea(child: Scaffold(body: MyHomePage('Cupertino Tab Bar Demo Home Page'))),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage(this.title);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var navigatorKeyList = [GlobalKey<NavigatorState>(), GlobalKey<NavigatorState>()];
var currentIndex = 0;
var controller = CupertinoTabController(initialIndex: 0);
#override
Widget build(BuildContext context) {
return CupertinoTabScaffold(
controller: controller,
tabBar: CupertinoTabBar(
onTap: (index) {
if (currentIndex == index) {
// Navigate to the tab's root route
navigatorKeyList[index].currentState.popUntil((route) {
return route.isFirst;
});
}
currentIndex = index;
},
items: [
BottomNavigationBarItem(title: Text('Tab 1'), icon: Icon(Icons.ac_unit)),
BottomNavigationBarItem(title: Text('Tab 2'), icon: Icon(Icons.ac_unit)),
],
),
tabBuilder: (BuildContext _, int index) {
switch (index) {
case 0:
return CupertinoTabView(
navigatorKey: navigatorKeyList[index],
routes: {
'/': (context) => WillPopScope(
child: Page1(),
onWillPop: () => Future<bool>.value(true),
),
'page1b': (context) => Page1b(),
'page1c': (context) => Page1c(),
},
);
case 1:
return CupertinoTabView(
navigatorKey: navigatorKeyList[index],
routes: {
'/': (context) => WillPopScope(
child: Page2(controller),
onWillPop: () => Future<bool>.value(true),
)
},
);
default:
return Text('Index must be less than 2');
}
},
);
}
}
// Tab1 Page1
class Page1 extends StatelessWidget {
Page1();
#override
Widget build(BuildContext context) {
return BaseContainer(
Column(
children: <Widget>[
Container(
child: Text(
'Tab1',
style: Theme.of(context).textTheme.headline4,
),
),
FlatButton(
color: Colors.lightGreen,
child: Text('Go to Tab1 Page2'),
onPressed: () {
Navigator.pushNamed(context, 'page1b');
},
)
],
),
);
}
}
// Tab1 Page2
class Page1b extends StatelessWidget {
Page1b();
#override
Widget build(BuildContext context) {
return BaseContainer(
Column(
children: <Widget>[
Container(
child:
Text('Tab1 Page2', style: Theme.of(context).textTheme.headline4),
),
FlatButton(
color: Colors.lightGreen,
child: Text('Go to Tab1 Page3'),
onPressed: () {
Navigator.pushNamed(context, 'page1c');
},
)
],
),
);
}
}
// Tab2
class Page2 extends StatelessWidget {
final CupertinoTabController controller;
const Page2(this.controller);
#override
Widget build(BuildContext context) {
return BaseContainer(
Column(
children: <Widget>[
Container(
child: Text(
'Tab2',
style: Theme.of(context).textTheme.headline4,
),
),
FlatButton(
color: Colors.lightGreen,
child: Text('Go to Tab1 Page2 (TODO)'),
onPressed: () {
// TODO I want this to go to Tab1 Page2
this.controller.index = 0;
Navigator.of(context).pushNamed('page1b');
},
)
],
),
);
}
}
You can copy paste run full code below
Step 1: You can pass navigatorKeyList[0]) to Page2
Step 2: call navigatorKey.currentState.pushNamed("page1b"); and change index
code snippet
return CupertinoTabView(
navigatorKey: navigatorKeyList[index],
routes: {
'/': (context) => WillPopScope(
child: Page2(controller, navigatorKeyList[0]),
onWillPop: () => Future<bool>.value(true),
)
},
);
...
class Page2 extends StatelessWidget {
final CupertinoTabController controller;
final GlobalKey<NavigatorState> navigatorKey;
const Page2(this.controller, this.navigatorKey);
...
FlatButton(
color: Colors.lightGreen,
child: Text('Go to Tab1 Page2 (TODO)'),
onPressed: () {
navigatorKey.currentState.pushNamed("page1b");
this.controller.index = 0;
},
)
working demo
full code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Cupertino Tab Bar Demo',
theme: ThemeData(primarySwatch: Colors.blue, textTheme: TextTheme()),
home: SafeArea(
child:
Scaffold(body: MyHomePage('Cupertino Tab Bar Demo Home Page'))),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage(this.title);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var navigatorKeyList = [
GlobalKey<NavigatorState>(),
GlobalKey<NavigatorState>()
];
var currentIndex = 0;
var controller = CupertinoTabController(initialIndex: 0);
#override
Widget build(BuildContext context) {
return CupertinoTabScaffold(
controller: controller,
tabBar: CupertinoTabBar(
onTap: (index) {
if (currentIndex == index) {
// Navigate to the tab's root route
navigatorKeyList[index].currentState.popUntil((route) {
return route.isFirst;
});
}
currentIndex = index;
},
items: [
BottomNavigationBarItem(
title: Text('Tab 1'), icon: Icon(Icons.ac_unit)),
BottomNavigationBarItem(
title: Text('Tab 2'), icon: Icon(Icons.ac_unit)),
],
),
tabBuilder: (BuildContext _, int index) {
switch (index) {
case 0:
return CupertinoTabView(
navigatorKey: navigatorKeyList[index],
routes: {
'/': (context) => WillPopScope(
child: Page1(),
onWillPop: () => Future<bool>.value(true),
),
'page1b': (context) => Page1b(),
'page1c': (context) => Page1c(),
},
);
case 1:
return CupertinoTabView(
navigatorKey: navigatorKeyList[index],
routes: {
'/': (context) => WillPopScope(
child: Page2(controller, navigatorKeyList[0]),
onWillPop: () => Future<bool>.value(true),
)
},
);
default:
return Text('Index must be less than 2');
}
},
);
}
}
// Tab1 Page1
class Page1 extends StatelessWidget {
Page1();
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Container(
child: Text(
'Tab1',
style: Theme.of(context).textTheme.headline4,
),
),
FlatButton(
color: Colors.lightGreen,
child: Text('Go to Tab1 Page2'),
onPressed: () {
Navigator.pushNamed(context, 'page1b');
},
)
],
),
);
}
}
// Tab1 Page2
class Page1b extends StatelessWidget {
Page1b();
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Container(
child: Text('Tab1 Page2',
style: Theme.of(context).textTheme.headline4),
),
FlatButton(
color: Colors.lightGreen,
child: Text('Go to Tab1 Page3'),
onPressed: () {
Navigator.pushNamed(context, 'page1c');
},
)
],
),
);
}
}
class Page1c extends StatelessWidget {
Page1c();
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Container(
child: Text('Tab1 Page2',
style: Theme.of(context).textTheme.headline4),
),
FlatButton(
color: Colors.lightGreen,
child: Text('Go to Tab1 Page3'),
onPressed: () {
Navigator.pushNamed(context, 'page1c');
},
)
],
),
);
}
}
// Tab2
class Page2 extends StatelessWidget {
final CupertinoTabController controller;
final GlobalKey<NavigatorState> navigatorKey;
const Page2(this.controller, this.navigatorKey);
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Container(
child: Text(
'Tab2',
style: Theme.of(context).textTheme.headline4,
),
),
FlatButton(
color: Colors.lightGreen,
child: Text('Go to Tab1 Page2 (TODO)'),
onPressed: () {
navigatorKey.currentState.pushNamed("page1b");
this.controller.index = 0;
},
)
],
),
);
}
}
full code 2
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Cupertino Tab Bar Demo',
theme: ThemeData(primarySwatch: Colors.blue, textTheme: TextTheme()),
home: SafeArea(
child:
Scaffold(body: MyHomePage('Cupertino Tab Bar Demo Home Page'))),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage(this.title);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var navigatorKeyList = [
GlobalKey<NavigatorState>(),
GlobalKey<NavigatorState>()
];
int currentIndex = 0;
var controller = CupertinoTabController(initialIndex: 0);
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return CupertinoTabScaffold(
controller: controller,
tabBar: CupertinoTabBar(
onTap: (index) {
if (currentIndex == index) {
// Navigate to the tab's root route
navigatorKeyList[index].currentState.popUntil((route) {
return route.isFirst;
});
}
currentIndex = index;
},
items: [
BottomNavigationBarItem(
title: Text('Tab 1'), icon: Icon(Icons.ac_unit)),
BottomNavigationBarItem(
title: Text('Tab 2'), icon: Icon(Icons.ac_unit)),
],
),
tabBuilder: (BuildContext _, int index) {
switch (index) {
case 0:
return CupertinoTabView(
navigatorKey: navigatorKeyList[index],
routes: {
'/': (context) => WillPopScope(
child: Page1(controller, navigatorKeyList[1]),
onWillPop: () => Future<bool>.value(true),
),
'page1b': (context) => Page1b(),
'page1c': (context) => Page1c(),
},
);
case 1:
return CupertinoTabView(
navigatorKey: navigatorKeyList[index],
routes: {
'/': (context) => WillPopScope(
child: Page2(controller, navigatorKeyList[0]),
onWillPop: () => Future<bool>.value(true),
)
},
);
default:
return Text('Index must be less than 2');
}
},
);
}
}
// Tab1 Page1
class Page1 extends StatelessWidget {
final CupertinoTabController controller;
final GlobalKey<NavigatorState> navigatorKey;
const Page1(this.controller, this.navigatorKey);
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Container(
child: Text(
'Tab1',
style: Theme.of(context).textTheme.headline4,
),
),
FlatButton(
color: Colors.lightGreen,
child: Text('Go to Tab2 Page2'),
onPressed: () async {
controller.index = 1;
await Future.delayed(Duration(seconds: 1), () {});
navigatorKey.currentState.pushNamed("/");
},
)
],
),
);
}
}
// Tab1 Page2
class Page1b extends StatelessWidget {
Page1b();
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Container(
child: Text('Tab1 Page2',
style: Theme.of(context).textTheme.headline4),
),
FlatButton(
color: Colors.lightGreen,
child: Text('Go to Tab1 Page3'),
onPressed: () {
Navigator.pushNamed(context, 'page1c');
},
)
],
),
);
}
}
class Page1c extends StatelessWidget {
Page1c();
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Container(
child: Text('Tab1 Page2',
style: Theme.of(context).textTheme.headline4),
),
FlatButton(
color: Colors.lightGreen,
child: Text('Go to Tab1 Page3'),
onPressed: () {
Navigator.pushNamed(context, 'page1c');
},
)
],
),
);
}
}
// Tab2
class Page2 extends StatelessWidget {
final CupertinoTabController controller;
final GlobalKey<NavigatorState> navigatorKey;
const Page2(this.controller, this.navigatorKey);
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Container(
child: Text(
'Tab2',
style: Theme.of(context).textTheme.headline4,
),
),
FlatButton(
color: Colors.lightGreen,
child: Text('Go to Tab1 Page2 (TODO)'),
onPressed: () async {
navigatorKey.currentState.pushNamed("page1b");
await Future.delayed(Duration(seconds: 1), () {});
this.controller.index = 0;
},
)
],
),
);
}
}
full code 3
return CupertinoTabView(
navigatorKey: navigatorKeyList[index],
routes: {
'/': (context) => WillPopScope(
child: Page1(controller, navigatorKeyList),
onWillPop: () => Future<bool>.value(true),
),
'page2b': (context) => Page2b(),
'page3b': (context) => Page3b(),
},
);
...
import 'package:cupertino_tab_bar/base_widget.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class Page1 extends StatelessWidget {
final CupertinoTabController controller;
final List<GlobalKey<NavigatorState>> navigatorKeyList;
const Page1(this.controller, this.navigatorKeyList);
#override
Widget build(BuildContext context) {
return BaseContainer(
Column(
children: <Widget>[
Container(
child: Text(
'Tab1',
style: Theme.of(context).textTheme.headline4,
),
),
FlatButton(
color: Colors.lightGreen,
child: Text('Go to Tab2 Page2'),
onPressed: () async{
controller.index = 1;
await Future.delayed(Duration(seconds: 1), () {});
navigatorKeyList[1].currentState.pushNamed("page2b");
},
),
FlatButton(
color: Colors.lightGreen,
child: Text('Go to Tab3 Page2'),
onPressed: () async{
controller.index = 2;
await Future.delayed(Duration(seconds: 1), () {});
navigatorKeyList[2].currentState.pushNamed("page3b");Navigator.pushNamed(context, 'page3b');
},
)
],
),
);
}
}
how to setState public var to another page?
int x = 1;
that was in public
in the first page text(x) i want to setstate from the other page
my first page is
class AddFullRequest extends StatefulWidget {
#override
_AddFullRequestState createState() => _AddFullRequestState();
}
class _AddFullRequestState extends State<AddFullRequest> {
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Text(x),
GestureDetector(
onTap: (){
Navigator.of(context).push(new MaterialPageRoute(
builder: (BuildContext context) => AddItemScr()));
},
child: Text('goto'),
),
],
),
);
}
in the other page button to ++ the var in the first page
my other page is
class AddItemScr extends StatefulWidget {
#override
_AddItemScrState createState() => _AddItemScrState();
}
class _AddItemScrState extends State<AddItemScr> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: WillPopScope(onWillPop: (){
Navigator.of(context).pop();
},
child: Column(
children: <Widget>[
FlatButton(onPressed: (){setState(() {
x++;
});}, child: Text('pluss'),)
],
),
),
);
}
}
please help me with this
You can use the callback pattern. In this example, a function (onPressed) is passed to the child. The child calls the function when a button is pressed:
class AddFullRequest extends StatefulWidget {
#override
_AddFullRequestState createState() => _AddFullRequestState();
}
class _AddFullRequestState extends State<AddFullRequest> {
int _x = 0;
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Text("$_x"),
GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => AddItemScr(
onPressed: () => setState(() => _x++),
),
),
);
},
child: Text('goto'),
),
],
),
);
}
}
class AddItemScr extends StatelessWidget {
final VoidCallback onPressed;
const AddItemScr({
Key key,
#required this.onPressed,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
FlatButton(
onPressed: onPressed,
child: Text('Increment'),
),
],
),
);
}
}
You can pass variables between screens. NavigatorState#pop supports passing objects that you can await in the previous screen and set it to it's value.
class AddFullRequest extends StatefulWidget {
#override
_AddFullRequestState createState() => _AddFullRequestState();
}
class _AddFullRequestState extends State<AddFullRequest> {
int x = 0;
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Text('$x'),
GestureDetector(
onTap: () async {
final result = await Navigator.of(context).push<int>(
MaterialPageRoute(
builder: (_) => AddItemScr(variable: x),
),
);
x = result;
setState(() {});
},
child: Text('goto'),
),
],
),
);
}
}
class AddItemScr extends StatefulWidget {
final int variable;
AddItemScr({this.variable});
#override
_AddItemScrState createState() => _AddItemScrState();
}
class _AddItemScrState extends State<AddItemScr> {
int _variable;
#override
void initState() {
_variable = widget.variable;
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
FlatButton(
onPressed: () {
setState(() {
_variable++;
});
},
child: Text('pluss'),
),
FlatButton(
onPressed: () {
Navigator.of(context).pop(_variable);
},
child: Text('go back'),
),
],
),
);
}
}
I want to collect input data from the user and record it in a certain page. You will see what my program does (full code down below). But the code below, is having two problems.
first problem: The Data in the HistoryPage class is not getting stored correctly. For example when I press A then type 50, The HistoryPage will store it as 'Subtracted 50 on A (and the date)'. But when I enter a second input, such as 30 on B, the Page will show 'Subtracted 30 on A', 'Subtracted 30 on B'. Thus, the Value of A also changes.
Second problem:
count++;
print(count);
historyList.add(History(data: text.data, dateTime: DateTime.now()));
This part of the code is not working. I tried to make 'text' a global variable. But I cannot change the constructor in the class Tile with a global variable.
full code:
import 'package:flutter/material.dart';
import './globals.dart' as globals;
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HistoryPage()),
);
},
child: Text(value.toString()),
),
FlatButton(
child: Center(child: Text("Spent")),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Type()),
);
},
)
],
));
}
}
class Spent extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () => Navigator.pop(context)),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Tile(
text: Text(
"A",
style: TextStyle(fontSize: 20.0),
),
),
Tile(
text: Text(
"B",
style: TextStyle(fontSize: 20.0),
),
),
Tile(
text: Text(
"C",
style: TextStyle(fontSize: 20.0),
),
),
]))));
}
}
class Tile extends StatelessWidget {
final Text text;
Tile({this.text});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Type()),
);
},
child: text,
);
}
}
class Type extends StatefulWidget {
#override
TypeState createState() => TypeState();
}
class TypeState extends State<Type> {
final _controller = TextEditingController();
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () => Navigator.pop(context)),
),
body: Center(
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
TextFormField(
textInputAction: TextInputAction.done,
controller: _controller,
keyboardType: TextInputType.number),
FlatButton(
child: Text("Subract"),
onPressed: () {
if (int.tryParse(_controller.text) == null) return;
globals.enteredValue = int.parse(_controller.text);
setState(() {
value -= globals.enteredValue;
});
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MyApp()),
);
count++;
print(count);
historyList.add(History(data: text.data, dateTime: DateTime.now()));
},
),
])),
));
}
}
int value = 0;
int count = 0;
List<History> historyList = [];
class History {
String data;
DateTime dateTime;
History({
this.data,
this.dateTime,
});
}
class HistoryPage extends StatefulWidget {
#override
HistoryPageState createState() => HistoryPageState();
}
class HistoryPageState extends State<HistoryPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MyApp()),
);
}),
),
body: Container(
child: ListView.builder(
itemCount: historyList.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(
' Subtracted ${globals.enteredValue} on ${historyList[index].data} ${historyList[index].dateTime.toString()}'),
);
},
),
));
}
}
globals.dart
library numbers.globals;
int enteredValue = 0;
You can copy paste run full code below
Step 1: class History add enteredValue attribute
class History {
int enteredValue;
Step 2: historyList.add need enteredValue
historyList.add(History(
enteredValue: int.parse(_controller.text),
Step 3: class Type need final Text text;
class Type extends StatefulWidget {
final Text text;
Type({this.text});
Step 4: MaterialPageRoute(builder: (context) => Type(text: text)),
working demo
full code
import 'package:flutter/material.dart';
import './globals.dart' as globals;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HistoryPage()),
);
},
child: Text(value.toString()),
),
FlatButton(
child: Center(child: Text("Spent")),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Spent()),
);
},
)
],
));
}
}
class Spent extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () => Navigator.pop(context)),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Tile(
text: Text(
"A",
style: TextStyle(fontSize: 20.0),
),
),
Tile(
text: Text(
"B",
style: TextStyle(fontSize: 20.0),
),
),
Tile(
text: Text(
"C",
style: TextStyle(fontSize: 20.0),
),
),
]))));
}
}
class Tile extends StatelessWidget {
final Text text;
Tile({this.text});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Type(text: text)),
);
},
child: text,
);
}
}
class Type extends StatefulWidget {
final Text text;
Type({this.text});
#override
TypeState createState() => TypeState();
}
class TypeState extends State<Type> {
final _controller = TextEditingController();
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () => Navigator.pop(context)),
),
body: Center(
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
TextFormField(
textInputAction: TextInputAction.done,
controller: _controller,
keyboardType: TextInputType.number),
FlatButton(
child: Text("Subract"),
onPressed: () {
if (int.tryParse(_controller.text) == null) return;
globals.enteredValue = int.parse(_controller.text);
setState(() {
value -= globals.enteredValue;
});
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MyApp()),
);
count++;
print(count);
historyList.add(History(
enteredValue: int.parse(_controller.text),
data: widget.text.data,
dateTime: DateTime.now()));
},
),
])),
));
}
}
int value = 0;
int count = 0;
List<History> historyList = [];
class History {
int enteredValue;
String data;
DateTime dateTime;
History({
this.enteredValue,
this.data,
this.dateTime,
});
}
class HistoryPage extends StatefulWidget {
#override
HistoryPageState createState() => HistoryPageState();
}
class HistoryPageState extends State<HistoryPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MyApp()),
);
}),
),
body: Container(
child: ListView.builder(
itemCount: historyList.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(
' Subtracted ${historyList[index].enteredValue} on ${historyList[index].data} ${historyList[index].dateTime.toString()}'),
);
},
),
));
}
}