How to move to different navigation tabs - flutter

I am a beginner, just started learning flutter recently and i took a project as a challenge am stuck at this point. I have a separate widget file for my bottom navigator bar, and am using the bottom nav bar in my home screen. so how can i switch to different tabs to display different widgets. My code code below only display's home tab widget which is in the HomeScreen body. Assuming i want to display different widget for each tab how can i achieve that?
//Bottom Navbar widget
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:foodbyte/widgets/PopularFoodsWidget.dart';
class BottomNavBarWidget extends StatefulWidget {
#override
_BottomNavBarWidgetState createState() => _BottomNavBarWidgetState();
}
class _BottomNavBarWidgetState extends State<BottomNavBarWidget> {
int _currentIndex = 0;
#override
Widget build(BuildContext context) {
return BottomNavigationBar(
currentIndex: _currentIndex,
selectedItemColor: Colors.lightBlue,
type: BottomNavigationBarType.fixed,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text(
'Home',
),
backgroundColor: Colors.blueAccent,
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
title: Text(
'Search',
),
backgroundColor: Colors.blueAccent,
),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_basket),
title: Text(
'Orders',
),
backgroundColor: Colors.blueAccent,
),
BottomNavigationBarItem(
icon: Icon(FontAwesomeIcons.user),
title: Text(
'Account',
),
backgroundColor: Colors.blueAccent,
),
],
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
);
}
}
//HomeScreen
//This is my homescreen where am using the bottom nav bar widget
import 'package:flutter/material.dart';
import 'package:foodbyte/screens/categories.dart';
import 'package:foodbyte/widgets/top_menus.dart';
import 'package:foodbyte/widgets/BottomNavBarWidget.dart';
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Color(0xFFFAFAFA),
elevation: 0,
title: Text(
"Welcome to my prototype app!",
style: TextStyle(
color: Color(0xFF3a3737),
fontSize: 16,
fontWeight: FontWeight.w500),
),
brightness: Brightness.light,
actions: <Widget>[
IconButton(
icon: Icon(
Icons.notifications_none,
color: Color(0xFF3a3737),
),
onPressed: () {
// Navigator.push(context, ScaleRoute(page: SignInPage()));
})
],
),
// appBar: buildSearchBar(context),
body: Padding(
padding: const EdgeInsets.fromLTRB(10.0, 0, 10.0, 0),
child: ListView(
children: <Widget>[
buildCategoryRow('Bottom Nav', context),
SizedBox(height: 10.0),
TopMenus(),
],
),
),
bottomNavigationBar: BottomNavBarWidget(),
);
}
buildCategoryRow(String category, BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
"$category",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.w800,
),
),
FlatButton(
child: Text(
"See all (9)",
style: TextStyle(
color: Theme.of(context).accentColor,
),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) {
return Categories();
},
),
);
},
),
],
);
}
}

You can create list of screens or widgets as you like.
List _widgets[Widget1,Widget2,Widget3];
since you have _currentIndex, you can use it to show your desired screen in scafold body.
Scafold:...
body:_widgets[_currentIndex]

Your logic is wrong
you are using the bottom navigation bar on the home screen that is no a good way.
What you need is to use the Scaffold widget in the bottom nav bar class and pass the Indexed Stack widget to the body of its scaffold and use the children parameter of IndexStack and paste your Screens Names inside children widget.
and pass your bottom navigation bar widget to the bottom navigation bar parameter of this scaffold.

Related

Change Drawer Icon of Drawer Widget being returned from an external Class

I'm trying to change the icon and color of my drawer widget in Dart. I've found ways of doing it but none that apply to my scenario. My custom drawer widget is being returned from another class and so I can't change the leading icon in the home class where the app bar is or it will replace my current drawer. I won't show all the code because I don't believe it would be necessary. Any help would be appreciated.
My Current drawer and method of calling it:
Drawer class:
import 'package:flutter/material.dart';
import 'package:new_app/Users.dart';
import '../main.dart';
class MainDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: <Widget>[
Container(
width: double.infinity,
padding: EdgeInsets.all(20),
color: Theme.of(context).primaryColor,
child: Center(
child: Column(
children: [
Container(
Menu Class/ home page:
import 'screens/drawer_main.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
return new Future(() => false);
},
child: Scaffold(
backgroundColor: Colors.blueGrey[900],
appBar: AppBar(
//backgroundColor: Colors.blueGrey[900],
backgroundColor: Colors.transparent,
automaticallyImplyLeading: true,
title: Text(
"Home Page",
style: TextStyle(color: Colors.white),
),
actions: <Widget>[
//Profile Pic
IconButton(
icon: Icon(Icons.circle, color: Colors.white),
tooltip: 'Comment Icon',
onPressed: () {},
),
MainPopUp(), //IconButton
],
//IconButton
brightness: Brightness.dark,
),
//Current Method of Calling the Drawer:
drawer: MainDrawer(),
body: Center(
Add the leading property in the App Bar and then call the Drawer Widget Programmatically.
Scaffold(
backgroundColor: Colors.blueGrey[900],
appBar: AppBar(
//backgroundColor: Colors.blueGrey[900],
leading: Builder(
builder: (context) => IconButton(
icon: Icon(Icons.menu_rounded),
onPressed: () => Scaffold.of(context).openDrawer(),
),
),
backgroundColor: Colors.transparent,
automaticallyImplyLeading: true,
title: Text(
"Home Page",
style: TextStyle(color: Colors.white),
),
actions: <Widget>[
//Profile Pic
IconButton(
icon: Icon(Icons.circle, color: Colors.white),
tooltip: 'Comment Icon',
onPressed: () {},
),
MainPopUp(), //IconButton
],
//IconButton
brightness: Brightness.dark,
),
//Current Method of Calling the Drawer:
drawer: MainDrawer(),
Add a leading inside AppBar() and open drawer programatically.
AppBar(
leading: InkWell(
child: Icon(
//your preferred icon
Icons.camera
),
onTap: () {
Scaffold.of(context).openDrawer();
},
),
)

Switch screen in flutter without context in flutter

I have this dart file(app_bar.dart) and am storing Appbars inside it and i have logged_home.dart file where am calling the app_bar.dart from. Now i want to be able to navigate to a new screen when i click next screen it sends me to PostData() while in app_bar.dart.
app_bar.dart:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:kopala_dictionary/screens/authenticate/login.dart';
import 'package:kopala_dictionary/screens/author/post_data.dart';
import 'package:kopala_dictionary/screens/home/unlogged_home.dart';
//for logged in user
final loggedBar = AppBar(
title: Text('Kopalaz Dictionary'),
backgroundColor: Colors.green,
elevation: 0.0,
actions: <Widget>[
FlatButton.icon(
color: Colors.white,
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => PostData()));
},
icon: Icon(Icons.add),
label: Text(
'Post',
style: TextStyle(color: Colors.white),
)),
],
);
//For unlogged users
final unloggedBar = AppBar(
title: Text('Kopalaz Dictionary'),
backgroundColor: Colors.green,
elevation: 0.0,
);
logged_home.dart:
import 'package:flutter/material.dart';
import 'package:kopala_dictionary/screens/wrapper.dart';
import 'package:kopala_dictionary/services/auth.dart';
import 'package:kopala_dictionary/shared/app_bar.dart';
class LoggedInUserHome extends StatelessWidget {
final AuthService _auth = AuthService();
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.green[10],
appBar: loggedBar,
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text(
'Kopalationary Menu',
style: TextStyle(color: Colors.white),
),
decoration: BoxDecoration(
color: Colors.green,
),
),
ListTile(
title: Text('Home'),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => Wrapper()));
},
),
ListTile(
title: Text(
'My profile',
),
onTap: () {},
),
ListTile(
title: Text('Logout'),
onTap: () async {
dynamic result = await _auth.logoutUser();
},
),
ListTile(
title: Text(
'About',
),
onTap: () {},
),
],
),
),
body: Center(
child: Text('Development in progress!'),
),
);
}
}
do not forget that in Flutter everything is a widget !
So my advice would be to create functions which returns a widget:
import 'package:flutter/material.dart';
//for logged in user
AppBar loggedBar(BuildContext context) {
return AppBar(
title: Text('Kopalaz Dictionary'),
backgroundColor: Colors.green,
elevation: 0.0,
actions: <Widget>[
FlatButton.icon(
color: Colors.white,
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => PostData()));
},
icon: Icon(Icons.add),
label: Text(
'Post',
style: TextStyle(color: Colors.white),
)),
],
);
}
//For unlogged users
AppBar unloggedBar(BuildContext context) {
return AppBar(
title: Text('Kopalaz Dictionary'),
backgroundColor: Colors.green,
elevation: 0.0,
);
}
Do keep in mind that flutter does a lot in the background and it is therefore better practice not to store widget in global variable. If you need to access those widgets from different part of your app you should look into Inherited Widget or other form of state management (see list here).
see below link:
Navigate without context in Flutter with a Navigation Service
https://medium.com/flutter-community/navigate-without-context-in-flutter-with-a-navigation-service-e6d76e880c1c
also, you can use GetX library

Flutter - Multi Page Navigation using bottom navigation bar icons

I'm trying to navigate to different pages within my app using the icons in my bottom navigation bar. I have tried many tutorials and can't seem to work out the best way to achieve this. I have created my Homepage (code below) and 2 additional pages, Inbox and Signin, both return simple scaffolds.
Firstly i'm interested to know if this is the best way to do what i'm trying to achieve and second, how can my code be altered to allow me to navigate to different pages depending on which icon is tapped. I'm aware that the code below doesn't execute, i'm just trying to show what i've tried.
My code:
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
_onTap(int index) {
Navigator.of(context)
.push(MaterialPageRoute<Null>(builder: (BuildContext context) {
return _children[_currentIndex];
}));}
final List<Widget> _children = [
HomePage(),
InboxPage(),
SignInPage()
];
int _currentIndex = 0;
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return Scaffold(
appBar: PreferredSize(preferredSize: Size(double.infinity, 75),
child: AppBar(
elevation: 0.0,
centerTitle: false,
title: Column(
children: <Widget>[
Align(
alignment: Alignment.centerLeft,
child: Text(
currentDate,
textAlign: TextAlign.left,
style: TextStyle(
color: titleTextColor,
fontWeight: subTitleFontWeight,
fontFamily: titleFontFamily,
fontSize: subTitleFontSize),
),
),
SizedBox(
height: 15,
),
Align(
alignment: Alignment.centerLeft,
child: Text(
'Some text here',
style: TextStyle(
color: titleTextColor,
fontWeight: titleTextFontWeight,
fontFamily: titleFontFamily,
fontSize: titleFontSize),
),
),
],
),
backgroundColor: kPrimaryColor,
shape: titleBarRounding
),
),
body: BodyOne(),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(Icons.mail),
title: Text('Inbox'),
),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle),
title: Text('Account'),
)
],
onTap: () => _onTap(_currentIndex),
),);
}
}
Thanks in advance.
The screen you are in can't be part of the Screens you're navigating to and you don't need to push a new screen each time you just have to change selectedPage, this is an example of how it should look:
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int selectedPage = 0;
final _pageOptions = [
HomeScreen(),
InboxScreen(),
SignInScreen()
];
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: _pageOptions[selectedPage],
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.home, size: 30), title: Text('Home')),
BottomNavigationBarItem(icon: Icon(Icons.mail, size: 30), title: Text('Inbox')),
BottomNavigationBarItem(icon: Icon(Icons.account_circle, size: 30), title: Text('Account')),
],
selectedItemColor: Colors.green,
elevation: 5.0,
unselectedItemColor: Colors.green[900],
currentIndex: selectedPage,
backgroundColor: Colors.white,
onTap: (index){
setState(() {
selectedPage = index;
});
},
)
);
}
}
Let me know if you need more explanation.
The input parameter of the _onTap function is unused and needs to be deleted.
_onTap() {
Navigator.of(context)
.push(MaterialPageRoute(builder: (BuildContext context) => _children[_currentIndex])); // this has changed
}
In the onTap of the BottomNavigationBar you need to change the _currentIndex and then call the _onTap function which navigates to the selected screen.
onTap: (index) {
setState(() {
_currentIndex = index;
});
_onTap();
},
You can add this BottomNavigationBar to all of the screens, but pay attention to the initial value of the _currentIndex that changes according to the screen you're putting the BottomNavigationBar in.
Full code:
_onTap() { // this has changed
Navigator.of(context)
.push(MaterialPageRoute(builder: (BuildContext context) => _children[_currentIndex])); // this has changed
}
final List<Widget> _children = [
HomePage(),
InboxPage(),
SignInPage()
];
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return Scaffold(
appBar: PreferredSize(
preferredSize: Size(double.infinity, 75),
child: AppBar(
elevation: 0.0,
centerTitle: false,
title: Column(
children: <Widget>[
Align(
alignment: Alignment.centerLeft,
child: Text(
currentDate,
textAlign: TextAlign.left,
style: TextStyle(
color: titleTextColor,
fontWeight: subTitleFontWeight,
fontFamily: titleFontFamily,
fontSize: subTitleFontSize),
),
),
SizedBox(
height: 15,
),
Align(
alignment: Alignment.centerLeft,
child: Text(
'Some text here',
style: TextStyle(
color: titleTextColor,
fontWeight: titleTextFontWeight,
fontFamily: titleFontFamily,
fontSize: titleFontSize),
),
),
],
),
backgroundColor: kPrimaryColor,
shape: titleBarRounding
),
),
body: BodyOne(),
body: Container(),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(Icons.mail),
title: Text('Inbox'),
),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle),
title: Text('Account'),
)
],
onTap: (index) { // this has changed
setState(() {
_currentIndex = index;
});
_onTap();
},
),
);
}
The best way to do it is creating a wrapper to your screens. Like this:
class Wrapper extends StatefulWidget {
Wrapper();
_WrapperState createState() => _WrapperState();
}
class _WrapperState extends State<Wrapper> {
int _currentIndex = 0;
final List<Widget> _children = [
HomePage(),
InboxPage(),
SignInPage()
];
void onTabTapped(int index) {
setState(() {
_currentIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: _children[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
onTap: onTabTapped,
currentIndex: _currentIndex,
items:[
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(Icons.mail),
title: Text('Inbox'),
),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle),
title: Text('Account'),
)
],
),
);
}
}

Trying to add a pageview controller without success....completely new at this

I am completely new at coding and of course I am trying to tackle one of the largest projects I can think of.... anyways. I am running into a huge wall when it comes to my current stage of coding. I have a defaultTabController at the upper portion of the screen with the functionality to switch in between two tabs. I would also like to have a bottomNavigationBar at the bottom of the application with 5 buttons that navigate to additional pages.
I have been attempting to add this code PageView(controller: _pageController, children: <Widget>[],) to the body of my code, yet I am either getting an overload of errors or only the top or bottom nav bars are active. If someone could show me what I'm doing wrong, I would be so grateful!
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
int _currentTab = 0;
PageController _pageController;
#override
void initState() {
super.initState();
_pageController = PageController();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: DefaultTabController(
length: 2,
child: Scaffold(
extendBodyBehindAppBar: true,
extendBody: true,
appBar: AppBar(
backgroundColor:
Colors.grey.withOpacity(0.5),
title: Text(
'TREBLE',
style: TextStyle(
color: Colors.black,
fontFamily: "treblefont",
fontSize: (33.0)
),
),
bottom: TabBar(
tabs: <Widget>[
Tab(text: "Following"),
Tab(text: "trending"),
],
)
),
body:
TabBarView(
children: <Widget>[
FeedScreen(),
TrendingScreen(),
],
),
bottomNavigationBar: CupertinoTabBar(
currentIndex: _currentTab,
onTap: (int index) {
setState(() {
_currentTab = index;
});
},
activeColor: Colors.black,
backgroundColor: Colors.white.withOpacity(0.5),
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.home,
size: 32.0,
),
),
BottomNavigationBarItem(
icon: Icon(
Icons.search,
size: 32.0,
),
),
BottomNavigationBarItem(
icon: Icon(
Icons.camera_enhance,
size: 32.0,
),
),
BottomNavigationBarItem(
icon: Icon(
Icons.notifications,
size: 32.0,
),
),
BottomNavigationBarItem(
icon: Icon(
Icons.account_circle,
size: 32.0,
),
),
],
),
),
),
);
}
}
I attempt to insert the code here:
)
),
body:
PageView(controller: _pageController, children: <Widget>[],)
TabBarView(
children: <Widget>[
FeedScreen(),
TrendingScreen(),
],
),
bottomNavigationBar: CupertinoTabBar(
currentIndex: _currentTab,
onTap: (int index) {
setState(() {
_currentTab = index;
});
},
line of code screenshot
Specific error readout screenshot

why flutter BottomNavigationBar changes the icon but does not change the page?

Im new to coding and flutter and I have been trying to make my bottomNavigationBar change pages from home page to chatroom but what ever I try is not working , I watched many videos but their bottomNavigationBar is inside their body and when I apply what they are doing I get the red line under my padding right after body and return Scaffold( right under this parenthesis before my appBar: image link is at the end of the code
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:trading/core/const.dart';
import 'package:trading/models/apartment_model.dart';
import 'package:trading/pages/chat.dart';
import 'package:trading/pages/detail_page.dart';
class Homepage extends StatefulWidget {
#override
_HomepageState createState() => _HomepageState();
}
class _HomepageState extends State<Homepage> {
var data = ApartmentModel.list;
int _selectedIndex = 0;
List<Widget> `enter code here`pages=[
Homepage(),
Chatroom(),
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
title: Text(
"find your product",
style: TextStyle(color: Colors.black87, fontWeight: FontWeight.bold),
),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.search,
color: Colors.black38,
),
onPressed: () {}),
IconButton(
icon: Icon(
Icons.filter_list,
color: Colors.black38,
),
onPressed: () {}),
],
),
bottomNavigationBar:
BottomNavigationBar(
showSelectedLabels: false,
showUnselectedLabels: false,
type: BottomNavigationBarType.fixed,
selectedItemColor: AppColors.stylecolor,
unselectedItemColor: Colors.black38,
currentIndex: _selectedIndex,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home), title: Text("datsa")),
BottomNavigationBarItem(
icon: Icon(Icons.chat), title: Text("data"),),
BottomNavigationBarItem(
icon: Icon(Icons.person), title: Text("data")),
],
),
body:
pages.elementAt(_selectedIndex),
Padding(
padding: EdgeInsets.all(16.0),
child:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"65 result in your area",
style: TextStyle(color: Colors.black38),
),
Expanded(
child: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: data.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => DetailPage(
data[index]
),
),
);
},
child: _buildItem(context, index));
},
),
),
// Container( child: _builBottomNavigationBar),
],
),
),
);
}
here is a pic of the red line that I was saying
body can take one widget not more, you assign pages and padding if you want both you must use a column
You have to make a List of Widgets containing your pages, and in the body you populate the Widget according to the Selected Index.
Example:
List<Widget> pages=[
Dashboard(),
Profile(),
Settings(),
];
then show the page in the body as:
body:
pages.elementAt(_selectedIndex),