Navigation to sub page(nasted Navigation) - flutter

I love to design an app with features like the ones in this Gif
1-Bottom Navigation bar exists on every page(done)
2-pressing on the icon change only part of the page
My Main to move between pages
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int selectedPage = 2;
final _pageOptions = [const PageOne(),const PageTwo(),const PageThree()];
#override
Widget build(BuildContext context) {
return Scaffold(
body: _pageOptions[selectedPage],
bottomNavigationBar: BottomNavigationBar(
items:const [
BottomNavigationBarItem(icon: Icon(Icons.add), label: ""),
BottomNavigationBarItem(icon: Icon(Icons.abc), label: ""),
BottomNavigationBarItem(icon: Icon(Icons.access_alarm), label: ""),
],
onTap: (int index) {
setState(() {
selectedPage = index;
});
},
),
);
}
}
pressing on the icon change only part of the page
Thanks in advance

I used Tabbar in Appbar and use the body of scafoldto change the sub-page
final List<Tab> myTabs = <Tab>[
Tab(text: 'LEFT'),
Tab(text: 'RIGHT'),
];
var Pages=[const PageFour(),const PageFive()];
int pageNum=1;
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
initialIndex: 1,
child: Scaffold(
appBar: AppBar(
bottom:TabBar(
tabs: myTabs,
onTap: (value) {
setState(() {
pageNum=value;
});
}
),
),
),
)
body: Pages[pageNum],}
I found some solutions using Getx or auto-router but it was difficult to understand it for me as a beginner I hope this answer helps whoever facing the same problem despite I didn't know how to navigate using the page itself as shown in Gif if anyone knows how to do that please answer below.

Related

Bottom Navigation bar with back feature

I want to use the Bottom Navigation bar to move between pages the Bottom Navigation bar is exist on every page, and clicking the back button directs me to the home page
My main
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int selectedPage = 2;
final _pageOptions = [const PageOne(),const PageTwo(),const PageThree()];
#override
Widget build(BuildContext context) {
return Scaffold(
body: _pageOptions[selectedPage],
bottomNavigationBar: BottomNavigationBar(
items:const [
BottomNavigationBarItem(icon: Icon(Icons.add), label: ""),
BottomNavigationBarItem(icon: Icon(Icons.abc), label: ""),
BottomNavigationBarItem(icon: Icon(Icons.access_alarm), label: ""),
],
onTap: (int index) {
setState(() {
selectedPage = index;
});
},
),
);
}
}
by using This code I can move between pages but when clicking The back button I get out of the program.
Thanks in advance.
Wrap your Scaffold with a WillPopScope as shown below;
class _MyHomePageState extends State<MyHomePage> {
int selectedPage = 2;
final _pageOptions = [const PageOne(),const PageTwo(),const PageThree()];
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
setState(() {
selectedPage = 0;
});
return false;
},
child: Scaffold(
body: _pageOptions[selectedPage],
bottomNavigationBar: BottomNavigationBar(
items: const [
BottomNavigationBarItem(icon: Icon(Icons.add), label: ""),
BottomNavigationBarItem(icon: Icon(Icons.abc), label: ""),
BottomNavigationBarItem(icon: Icon(Icons.access_alarm), label: ""),
],
onTap: (int index) {
setState(() {
selectedPage = index;
});
},
),
),
);
}
}
The above answer will stop the back button exiting the app. However if you’d like to have the ability to return to the homepage / previous page you’ll need to implement routing.
Use the GoRouter package & follow the documentation to get it setup. You’ll need this for navigating & maintaining the navigation stack so you can go back and forth between pages properly.

Flutter - Navigating between pages

I'm making a simple app to learn a bit about Flutter but I'm having a problem navigating between my pages.
The app has only three pages (home, search, settings) and I made a simple navigation bar. Right now I'm using:
Navigator.of(context).pushReplacementNamed("/home");
The problem is that I would like to navigate between pages, without creating "new" pages. So for example, if I have a text field on the Search page and then I go to the Home page and back to the Search page, the input in the text field remains.
What is the best way of navigating between pages without pushing or popping "new" pages?
You can check out this example with bottom navigation bar for changing between widgets to show different views. You can follow this example to be able to create what you need.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
#override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
Text(
'Index 0',
style: optionStyle,
),
Text(
'Index 1',
style: optionStyle,
),
Text(
'Index 2',
style: optionStyle,
),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Tab 0',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Tab 1',
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'Tab 2',
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
}
Have an external TextEditingController.
class MyApp extends StatelessWidget {
final searchController = TextEditingController();
#override
Widget build(BuildContext context) {
return MaterialApp(
...
routes: {
'/search': (_) => SearchPage(searchController),
...
},
);
}
}
In SearchPage, use the passed searchController for the search field.
TextField(
...
controller: searchController,
)
If you literally don't want to create a new page.
SearchPage searchPage;
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
...
routes: {
'/search': (_) => searchPage ??= SearchPage(),
...
},
);
}
}
in flutter pushReplacementNamed will replace and dispose the current UI so what you need is just push.
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
So, I Recommend you read some of the following and I recommend using Get Plugin.
https://pub.dev/packages/get
https://medium.com/flutter/learning-flutters-new-navigation-and-routing-system-7c9068155ade
https://flutter.dev/docs/cookbook/navigation/navigation-basics

Where to write the network call in Flutter?

I have a BottomNavigationBar with 3 tabs. Consider I select a product in an e-commerce app from the pages inside the first BottomNavigationBarItem. I need to see that product in the second BottomNavigationBarItem(cart page). I have written the network call code in initState() of second BottomNavigationBarItem; but it will not be called when I go to that page and I can't see the recently added product to the cart. Is it better to write them in the build method itself? Writing them in the build method calls it every time I go to other tabs also.
Use FutureBuilder or StreamBuilder to network call and flow the data to UI
Hope this will help you
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _selectedPage = 0;
String _selectedProduct;
Widget getCurrentPage(){
switch(_selectedPage){
case 0:
return Page1((selectedProduct){
setState((){
this._selectedProduct = selectedProduct;
_selectedPage=1;
});});
case 1:
return Page2(this._selectedProduct);
case 2:
return Page3();
default:
return Center(child:Text('Error'));
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: getCurrentPage(),
bottomNavigationBar: BottomNavigationBar(
onTap: (index){
setState((){
_selectedPage = index;
});
},
currentIndex: _selectedPage,
items: ['tab 1', 'tab 2', 'tab3'].map((e)=>BottomNavigationBarItem(
icon: Container(),
title: Text(e),
)).toList(),),
);
}
}
class Page1 extends StatelessWidget {
final Function(String) onProductClick;
const Page1(this.onProductClick);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title:Text('Page 1')),
body:Column(
children: <Widget>[
RaisedButton(
child: Text('Product 1'),onPressed: ()=>onProductClick('Product 1'),),
RaisedButton(
child: Text('Product 2'),onPressed: ()=>onProductClick('Product 2'),),
RaisedButton(
child: Text('Product 3'),onPressed: ()=>onProductClick('Product 3'),),
RaisedButton(
child: Text('Product 4'),onPressed: ()=>onProductClick('Product 4'),),
RaisedButton(
child: Text('Product 5'),onPressed: ()=>onProductClick('Product 5'),),
],)
);
}
}
class Page2 extends StatelessWidget {
final String selectedProduct;
const Page2(this.selectedProduct);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title:Text('Page 2')),
body:Center(child:Text(selectedProduct??'Nothing selected'))
);
}
}
class Page3 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title:Text('Page 3')),
body:Center(child:Text('Page 3'))
);
}
}

How To Fix Bottom navigation in flutter?

How to fix Bottom Navigation in Flutter?
MediaQuery.Of() called with context That does not contain a
MediaQuery.Bottom Navigation Not working.
This code Showing Error What is MediaQuery.Of() called with context That does not contain a MediaQuery?
import 'package:flutter/material.dart';
void main(){
runApp(Home());
}
class Home extends StatefulWidget{
#override
State<StatefulWidget> createState() => _HomeState();
}
class _HomeState extends State<Home>{
int currindex=0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Bottom Nav "),
),
body: Container(),
bottomNavigationBar: BottomNavigationBar(
currentIndex: currindex,
items:[BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text("Home"),
backgroundColor: Colors.blue
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
title: Text("Search"),
backgroundColor: Colors.blue
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
title: Text("Profile"),
backgroundColor: Colors.blue
),],
onTap: (index){
setState(() {
currindex=index;
});
},
));
}
}
it is because you are not using MaterialApp(), you need to use MaterialApp() in your widget tree
look at this demo....
void main() => runApp(Home());
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: //your Title,
theme: //your theme,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget{
#override
State<StatefulWidget> createState() => _HomePageState();
}
//and your _HomePageState widget goes here

Navigating to another page from drawer menu and setting title to app bar

i am new to flutter and would like someone to help me with code i found in github that i would like to use. take a look at the link below
https://github.com/JohannesMilke/drawer_example
this is an example of a navigational drawer. i like the way the developer coded it and would like to use this example. the problem is that the developer didnt implement navigating to another page. when you click on item in the drawer, it just print a message in the console.
i want to take this a step further. i want to modified the code so that when you click on a item it will navigate to another page and the drawer will b closed. the drawer icon should remain on the toolbar on the new page displayed. also, when you navigate to another page the title of that page should be set in the toolbar.
when i looked at the code , i have an idea where to change but i am not successful. i think i need to change the body tag at the bottom of the code. the problem is that i dont know how to call the DrawerWidgetState class in drawer_widget.dart file.
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
final String appTitle = 'Ttitle';
#override
Widget build(BuildContext context) => MaterialApp(
title: appTitle,
theme: ThemeData(
primaryColor: Colors.red,
textTheme: TextTheme(
subhead: TextStyle(
color: Colors.black.withOpacity(0.4),
),
),
dividerColor: Colors.black.withOpacity(0.4),
),
home: MainPage(appTitle: appTitle),
);
}
class MainPage extends StatefulWidget {
final String appTitle;
const MainPage({this.appTitle});
#override
MainPageState createState() => MainPageState();
}
class MainPageState extends State<MainPage> {
#override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: Text(widget.appTitle),
),
drawer: DrawerWidget(),
body: container()
);
}
i define the following function in drawer_widget.dart file
getDrawerItemWidget(int pos) {
print('testing');
switch (pos) {
case 0:
return new FirstFragment();
case 1:
return new SecondFragment();
case 2:
return new ThirdFragment();
default:
return new Text("Error");
}
}
but i dont know how to call it from Mainpage Body tag and set title accordingly. can someone help modify the code so that i can nagivate to another page and set title? full code is in
https://github.com/JohannesMilke/drawer_example
thanks in advance
Using the drawer_example library you need to make some small changes in order to make it work.
Over your drawer_widget.dart add this add the beginning:
typedef TitleCallback = void Function(String, int);
Once you do that, your Drawer StatefulWidget should looks this way:
class DrawerWidget extends StatefulWidget {
final TitleCallback callback;
final int tabIndex;
#override
DrawerWidgetState createState() => DrawerWidgetState();
DrawerWidget(this.callback, this.tabIndex);
}
and your initState:
#override
void initState() {
selectedDrawerIndex = widget.tabIndex;
selectedProfileIndex = 0;
super.initState();
}
This will be the constructor to pass the new value back to your main.dart file.
Inside the ListTile, you can add the following logic:
ListTile(
leading: Icon(item.icon),
title: Text(item.name),
selected: selectedDrawerIndex == currentIndex,
onTap: () {
final item = getOffsetIndex(drawerGroups, currentIndex);
print('Selected index $selectedDrawerIndex with name ${item.name}');
setState(() {
selectedDrawerIndex = currentIndex;
widget.callback(item.name, selectedDrawerIndex);
});
Navigator.pop(context); // to close the Drawer
},
)
If you can check, the line: widget.callback(item.name); sends the tab name over the callback and that logic can be applied any where you want to change your title. It can even be a hard coded title like:
widget.callback("Second Tab");
Now, going back to your main.dart file:
class MyApp extends StatefulWidget {
final String title;
ListExample(this.title);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Widget> _fragments = <Widget> [
Container(
child: Text("Fragment One"),
),
Container(
child: Text("Fragment Two"),
),
Container(
child: Text("Fragment Three"),
),
];
String titleAppBar = "Testing";
int tabIndex = 0;
#override
void initState() {
setState(() {
titleAppBar = widget.title;
});
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: widget.title,
home: Scaffold(
appBar: AppBar(
title: Text(titleAppBar),
),
drawer: DrawerWidget((title, index) {
setState(() {
titleAppBar = title;
tabIndex = index;
});
}, tabIndex),
body: _fragments[tabIndex],
),
);
}
}
Final Result:
Looking at the example on GitHub, it's overcomplicating something that's too easy with Flutter.
Here's a simple example on how to use a Drawer on Flutter:
main.dart
import 'package:flutter/material.dart';
import 'another_page.dart';
import 'home_page.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
// declaring your routes will allow you to push and remove everything from the stack (including the drawer) with pushNamedAndRemoveUntil()
routes: {
'home': (context) => HomePage(),
'anotherPage': (context) => AnotherPage(),
},
initialRoute: 'home',
);
}
}
home_page.dart (another_page.dart is exactly the same for illustration purpose)
import 'package:flutter/material.dart';
import 'menu_drawer.dart';
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: MenuDrawer(),
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: Text('Home'),
),
);
}
}
menu_drawer.dart
import 'package:flutter/material.dart';
class MenuDrawer extends StatelessWidget {
// Push the page and remove everything else
navigateToPage(BuildContext context, String page) {
Navigator.of(context).pushNamedAndRemoveUntil(page, (Route<dynamic> route) => false);
}
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
// This could be mapped from a List of items
children: <Widget>[
ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
onTap: () => navigateToPage(context, 'home'),
),
ListTile(
leading: Icon(Icons.panorama),
title: Text('Another page'),
onTap: () => navigateToPage(context, 'anotherPage'),
),
],
),
);
}
}
Final result: