----------
Here is the 1st-screenshot of my problem
This is the 2nd-second screenshot when after implementing single child scrolled view
I have created a navigation drawer and a Bottom navigation widget, i have face the following problems/
While opening drawer it says the drawer exceeds XX pixels so i wrapped it up in "Single child scroll view and now the drawer opens up like a whole page.
Also, when drawer is pressed the Bottom navigation overlaps it.
I have added images which you can see through my clicking above.
here is my piece of code.
class Mydrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
UserAccountsDrawerHeader(
accountName: Text('Name'),
accountEmail: Text('Username'),
currentAccountPicture: CircleAvatar(
backgroundColor: Colors.white,
child: Text('Hi'),
),
),
ListTile(
leading: Icon(Icons.home),
title: Text(
'Home Page',
),
onTap: () {
Navigator.of(context).pop();
Navigator.of(context).pushNamed(MyHomepage.route);
}),
ListTile(
leading: Icon(Icons.person),
title: Text(
'My Account',
),
onTap: () {
Navigator.of(context).pop();
Navigator.of(context).pushNamed(Account.route);
},
),
ListTile(
leading: Icon(Icons.assignment),
title: Text(
'My Lists',
),
onTap: () {
Navigator.of(context).pop();
Navigator.of(context).pushNamed(Mylist.route);
},
),
ListTile(
leading: Icon(Icons.bookmark),
title: Text(
'Wishlist',
),
onTap: () {
Navigator.of(context).pop();
Navigator.of(context).pushNamed(Wishlist.route);
},
),
Divider(),
ListTile(
leading: Icon(Icons.mail),
title: Text(
'Contact us',
),
onTap: () {
Navigator.of(context).pop();
Navigator.of(context).pushNamed(Contactus.route);
},
),
ListTile(
leading: Icon(Icons.info),
title: Text(
'Info & FAQ',
),
onTap: () {
Navigator.of(context).pop();
Navigator.of(context).pushNamed(Infofaq.route);
},
),
Divider(),
ListTile(
leading: Icon(Icons.lock_open),
title: Text(
'Logout',
),
onTap: () {
Navigator.pop(context);
},
),
],
),
),
),
);
}
}
Bottom Navigation Code
class Nav extends StatefulWidget {
#override
_NavState createState() => _NavState();
}
class _NavState extends State<Nav> {
int _selectedIndex = 0;
final List<Widget> _widgetOptions = [
NavHome(),
NavInspiration(),
NavNotification(),
NavMessages(),
];
void _onitemtap(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: _widgetOptions[_selectedIndex],
bottomNavigationBar: BottomNavigationBar(
showSelectedLabels: false,
showUnselectedLabels: false,
type: BottomNavigationBarType.fixed,
onTap: _onitemtap,
currentIndex: _selectedIndex,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(Icons.filter_none),
title: Text('Inspiration'),
),
BottomNavigationBarItem(
icon: Icon(Icons.notifications_none),
title: Text('Notifications'),
),
BottomNavigationBarItem(
icon: Icon(Icons.mail_outline),
title: Text('Messages'),
),
],
),
);
}
}
Main Dart
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter demo',
home: Nav(),
theme: ThemeData(
primarySwatch: Colors.blue,
),
//home: Homepage(),
//initialRoute: '/',
routes: {
MyHomepage.route: (_) => MyHomepage(),
Account.route: (_) => Account(),
Mylist.route: (_) => Mylist(),
Wishlist.route: (_) => Wishlist(),
Contactus.route: (_) => Contactus(),
Infofaq.route: (_) => Infofaq(),
},
);
}
}
----------
Check this!
It's work for me
use drawer part of scaffold().
The best thing that can be done here is, just like you have your Drawer seperate, create a seperate navbar class with no scaffold or body, just the navbar. Now, call both of these, the drawer and the navbar, in a third widget, which contains your scaffold. For changing the index, you can pass the function as a parameter to your navbar widget.
i have changed how u relay your codes, try implementing this in your code. and i have decomposed Nav(), so take in mind that im not using the Nav() as awhole
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: MainEntry(),
theme: ThemeData(
primarySwatch: Colors.blue,
),
//home: Homepage(),
//initialRoute: '/',
routes: {
MyHomepage.route: (_) => MyHomepage(),
Account.route: (_) => Account(),
Mylist.route: (_) => Mylist(),
Wishlist.route: (_) => Wishlist(),
Contactus.route: (_) => Contactus(),
Infofaq.route: (_) => Infofaq(),
},
);
}
}
class MainEntry extends StatefulWidget {
#override
_MainEntryState createState() => _MainEntryState();
}
class _MainEntryState extends State<MainEntry> {
#override
Widget build(BuildContext context) {
return MaterialApp(debugShowCheckedBanner: false,
home: Scaffold(
drawer: MyDrawer(),
body: _widgetOptions[_selectedIndex] //your body
bottomNavigationBar: BottomNavigationBar(
showSelectedLabels: false,
showUnselectedLabels: false,
type: BottomNavigationBarType.fixed,
onTap: _onitemtap,
currentIndex: _selectedIndex,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(Icons.filter_none),
title: Text('Inspiration'),
),
BottomNavigationBarItem(
icon: Icon(Icons.notifications_none),
title: Text('Notifications'),
),
BottomNavigationBarItem(
icon: Icon(Icons.mail_outline),
title: Text('Messages'),
),
],
)
)
);
}
}
Related
i have tried in the following way but it is not working please tell me the solutions
import 'package:book_recommendation_app/about.dart';
import 'package:book_recommendation_app/home.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
void onTap(menuItem) {
switch (menuItem) {
case 'item1':
print('item1 clicked');
break;
case 'item2':
print('item2 clicked');
break;
case 'item3':
print('item3 clicked');
break;
}
}
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
var menuItems = <String>['item1', 'item2', 'item3'];
return MaterialApp(
title: 'Book Reccomendation Demo',
home: Scaffold(
appBar: AppBar(
title: Text('Home'),
actions: <Widget>[
PopupMenuButton<String>(
onSelected: onTap,
itemBuilder: (BuildContext context) {
return menuItems.map((String choice) {
return PopupMenuItem<String>(
child: Text(choice),
value: choice,
);
}).toList();
})
],
),
body: searchBar(),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
const DrawerHeader(
decoration: BoxDecoration(
color: Colors.blue,
),
child: Text('Drawer Header'),
),
ListTile(
title: const Text('Item 1'),
onTap: () {
Navigator.pop(context);
},
),
ListTile(
title: const Text('About us'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AboutUs()),
);
Navigator.pop(context);
},
),
],
),
),
),
// home: const MyHomePage(title: 'Book Reccomendation Demo Home Page'),
);
}
}
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
var menuItems = <String>['item1', 'item2', 'item3'];
return MaterialApp(
title: 'Book Reccomendation Demo',
home: Scaffold(
appBar: AppBar(
title: Text('Home'),
actions: <Widget>[
PopupMenuButton<String>(
onSelected: onTap,
itemBuilder: (BuildContext context) {
return menuItems.map((String choice) {
return PopupMenuItem<String>(
child: Text(choice),
value: choice,
);
}).toList();
})
],
),
body: searchBar(),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
const DrawerHeader(
decoration: BoxDecoration(
color: Colors.blue,
),
child: Text('Drawer Header'),
),
ListTile(
title: const Text('Item 1'),
onTap: () {
Navigator.pop(context);
},
),
ListTile(
title: const Text('About us'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AboutUs()),
);
Navigator.pop(context);
},
),
],
),
),
),
// home: const MyHomePage(title: 'Book Reccomendation Demo Home Page'),
);
}
}
Do not call Navigator.pop(context) immediately afther calling Navigator.push. Because for me it looks like your currently pushing to the next screen, but immediately popping again so that it will never be reached.
In this ListTile
ListTile(
title: const Text('About us'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AboutUs()),
);
Navigator.pop(context);
},
),
You use Navigator.Push(context,MaterialPageRout(builder: (context) => AboutUs()));
then you use Navegator.pop(context);
that means you push a new screen then you closed it and here is the problem
you need just to remove this line Navigator.pop(context);
You can use GetX too for navigate your pages in easier way if you don't want to go with MaterialPageRoute.
ListTile(
title: const Text('About us'),
onTap: () {
Get.to(AboutUs());
Navigator.pop(context);
},
),
Pop the drawer before pushing to new screen,
Like
Navigator.pop(context);
Navigator.push(context,
MaterialPageRoute(builder: (context) => AboutUs(),
),
);
I'm facing an issue of "Multiple GlobalKeys in the Widget tree" while Navigation.
I have a BottomNavigationBar & a Drawer defined in the Scaffold of a Base Screen and in the body parameter of Scaffold I have multiple screens which I'm accessing with BottomNavigationBar. The thing is, I'm accessing the Drawer of the Base Screen from one of the multiple screens by using a GlobalKey, and everything's working fine but when I Navigate to the Base Screen from Another Screen then I get the above-mentioned error.
I have tried a solution of not using a static keyword while defining the key and it solves the error of navigation but then I can't access the Drawer because then I get another error of "method 'openDrawer' was called on null".
This is a separate class where I have defined the Key:
class AppKeys {
final GlobalKey<ScaffoldState> homeKey = GlobalKey<ScaffoldState>();
}
This is the Base Screen:
class Base extends StatefulWidget {
#override
_BaseState createState() => _BaseState();
}
class _BaseState extends State<Base> {
int selectedScreen = 0;
final screens = List<Widget>.unmodifiable([Home(), Cart(), Orders(), Help()]);
AppKeys appKeys = AppKeys();
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: MyDrawer(),
key: appKeys.homeKey,
body: screens[selectedScreen],
bottomNavigationBar: SizedBox(
height: 80,
child: BottomNavigationBar(
onTap: (val) {
setState(() {
selectedScreen = val;
});
},
currentIndex: selectedScreen,
selectedItemColor: AppColor.primary,
elevation: 20.0,
unselectedItemColor: Colors.grey,
showUnselectedLabels: true,
type: BottomNavigationBarType.fixed,
iconSize: 25,
selectedFontSize: 15,
unselectedFontSize: 15,
items: [
BottomNavigationBarItem(
icon: Icon(AnanasIcons.home), title: Text("Home")),
BottomNavigationBarItem(
icon: Icon(AnanasIcons.cart), title: Text("Cart")),
BottomNavigationBarItem(
icon: Icon(AnanasIcons.orders), title: Text("My Orders")),
BottomNavigationBarItem(
icon: Icon(AnanasIcons.help), title: Text("Help")),
],
),
),
);
}
}
This is the Home Screen from where I'm accessing the Drawer:
class Home extends StatelessWidget {
final AppKeys appKeys = AppKeys();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(
AnanasIcons.menu,
color: Colors.black,
),
onPressed: () {
appKeys.homeKey.currentState.openDrawer();
}),
backgroundColor: Theme.of(context).canvasColor,
title: Text("Hi"),
actions: [
IconButton(
icon: Icon(
Icons.person,
color: Colors.black,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Profile(),
));
})
],
),
body: Container(),
);
}
}
I've found the answer! Instead of pushing the route with the key, we need to remove all the routes from the stack till the screen where we have to go.
Here's the code for that:
Navigator.of(context).popUntil(ModalRoute.withName(Base.routeName));
I am relatively new to Flutter and am building an app that fetches data from an API and display it throughout the app on different widgets. I am using a Provider to perform the API calls and store the deserialized json in a property I then access in the initState function. Below is the widget tree of my main.dart, I want to then access the provider found here in the Dashboard page as this is where the value is required. I know what I am doing is wrong, but how much have I gotten it wrong?
runApp(MaterialApp(
home: LoginPage(),
routes: routes,
));
}
class SampleApp extends StatefulWidget {
#override
SampleAppState createState() => SampleAppState();
}
class SampleAppState extends State<SampleApp> {
int currentIndex = 0;
final List<Widget> childPages = [
Page1(),
Page2(),
Page3(),
Page4()
];
void onTapped(int index) {
setState(() {
currentIndex = index;
});
}
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => APIProvider())
],
child: Scaffold(
body: childPages[currentIndex],
bottomNavigationBar: BottomNavigationBar(
onTap: onTapped,
currentIndex: currentIndex,
fixedColor: Colors.lightBlue,
backgroundColor: Colors.white,
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: new Icon(Icons.dashboard),
title: new Text('Page 1'),
activeIcon: new Icon(
Icons.dashboard,
color: Colors.lightBlue,
)),
BottomNavigationBarItem(
icon: new Icon(Icons.list),
title: new Text('Page 2'),
activeIcon: new Icon(
Icons.list,
color: Colors.lightBlue,
)),
BottomNavigationBarItem(
icon: new Icon(Icons.collections_bookmark),
title: new Text('Page 3'),
activeIcon: new Icon(
Icons.collections_bookmark,
color: Colors.lightBlue,
)),
BottomNavigationBarItem(
icon: new Icon(Icons.person),
title: new Text('Page 4'),
activeIcon: new Icon(
Icons.person,
color: Colors.lightBlue,
)),
],
),
),
);
}
}
I then attempt to access the provider value in Page1 like so:
#override
void initState() {
valueFromProvider =
Provider.of<APIProvider>(context).providerValue;
super.initState();
}
Perhaps this is happening because the provider value I attempt to access in the Page1 widget is null, would pre-loading my provider solve this?
You aren't providing the Provider at the right time. In your case you add the MultiProvider at page1, but your context is already initialized so you can't access it. In order to properly access it, you must move the MultiProvider to where you initialize the app like the following:
runApp(
MaterialApp(
home: MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => APIProvider())
],
child:LoginPage()
),
routes: routes,
));
This should fix your issue.
I have a bottom navigation bar defined separately in a file, containing 5 items, and loading 5 pages (which doesn't have defined a bottom navigation bar). It should be present on 4 of the loaded pages but should disappear on the 5th page (CHAT). All the solutions I found online refers to hiding the bar while scrolling up or down, I think I'm quite close to the expected result but I didn't sort it out yet... The code for that "controller" that generates the B-N-Bar is below, a screenshot with the bottom as well. Thank you.
class BottomNavigationBarController extends StatefulWidget {
#override
_BottomNavigationBarControllerState createState() =>
_BottomNavigationBarControllerState();
}
class _BottomNavigationBarControllerState
extends State<BottomNavigationBarController> {
final List<Widget> pages = [
MyHome(
key: PageStorageKey('Page1'),
),
MyStats(
key: PageStorageKey('Page2'),
),
MyCategories(
key: PageStorageKey('Page3'),
),
MyPeopleList(
key: PageStorageKey('Page4'),
),
MyChat(
key: PageStorageKey('Page5'),
),
];
final PageStorageBucket bucket = PageStorageBucket();
int _selectedIndex = 0;
Widget _bottomNavigationBar(int selectedIndex) => BottomNavigationBar(
onTap: (int index) => setState(() => _selectedIndex = index),
currentIndex: selectedIndex,
type: BottomNavigationBarType.fixed,
//
iconSize: 24,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text(
'HOME',
),
),
BottomNavigationBarItem(
icon: Icon(Icons.insert_chart),
title: Text(
'STATS',
),
),
BottomNavigationBarItem(
icon: Icon(Icons.view_list),
title: Text(
'INVENTORY',
),
),
BottomNavigationBarItem(
icon: Icon(Icons.group),
title: Text(
'PEOPLE',
),
),
BottomNavigationBarItem(
icon: Icon(Icons.forum),
title: Text(
'CHAT',
),
),
],
);
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: _bottomNavigationBar(_selectedIndex),
body: PageStorage(
child: pages[_selectedIndex],
bucket: bucket,
),
);
}
}
I did it with an IF/Else in the bottom:
#override
Widget build(BuildContext context) {
if (_selectedIndex < 4) {
return Scaffold(
bottomNavigationBar: _bottomNavigationBar(_selectedIndex),
body: PageStorage(
child: pages[_selectedIndex],
bucket: bucket,
),
);
} else {
return Scaffold(
body: PageStorage(
child: pages[_selectedIndex],
bucket: bucket,
),
);
}
}
I work on flutter and I make an app with 5 tabs, using a BottomNavigationBar, who change the currently displayed content.
When I tap on a tab, the content updates to the new content, but the tabs icon doesn't change.
I have tried to change the BottomNavigationBarType but that changes nothing...
here is base page widget:
class Home extends StatefulWidget {
Home({Key key}) : super(key: key);
#override
_Home createState() => _Home();
}
class _Home extends State<Home> {
int _selectedIndex = 0;
static List<Widget> _widgetOptions = <Widget>[
HomePage(),
CreateTrain(),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
print(_selectedIndex);
return Scaffold(
body: _widgetOptions.elementAt(_selectedIndex),
bottomNavigationBar: BottomNavigationBar(
currentIndex: 0, // this will be set when a new tab is tapped
items: [
BottomNavigationBarItem(
icon: new Icon(Icons.home),
title: new Text('Home'),
),
BottomNavigationBarItem(
icon: new Icon(Icons.assignment),
title: new Text('Training'),
),
BottomNavigationBarItem(
icon: new Icon(Icons.play_arrow),
title: new Text('start'),
),
BottomNavigationBarItem(
icon: new Icon(Icons.insert_chart),
title: new Text('Stats'),
),
BottomNavigationBarItem(
icon: Icon(Icons.person), title: Text('Profile'))
],
selectedFontSize: 12,
unselectedFontSize: 12,
selectedItemColor: Colors.amber[800],
unselectedItemColor: Colors.grey[500],
showUnselectedLabels: true,
type: BottomNavigationBarType.fixed,
onTap: _onItemTapped,
),
);
}
}
Here is HomePage widget:
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: true,
title: const Text(
'Home',
style: TextStyle(
color: Colors.black,
fontSize: 30,
),
),
backgroundColor: _bgColor,
),
body: Text('data'),
);
}
}
Thanks for your help.
In your code
currentIndex: 0, // this will be set when a new tab is tapped
This should be
currentIndex: _selectedIndex, // this will be set when a new tab is tapped