What is the best why to navigate to a page in flutter using the default Material Drawer.
I'm still learning how to work with Flutter.
In Android we used to anvigate to a fragment page, but how does this work in Flutter ?
I just want to understand how to navigate to an drawer item without without using bloc's.
class MdDrawer extends StatelessWidget {
final String title;
MdDrawer({Key key, this.title}) : super(key: key);
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Text('MyPage'),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
UserAccountsDrawerHeader(
accountName: const Text(_AccountName),
accountEmail: const Text(_AccountEmail),
currentAccountPicture: CircleAvatar(
backgroundColor: Colors.brown,
child: Text(_AccountAbbr),
),
),
ListTile(
leading: Icon(Icons.lightbulb_outline),
title: Text('Notes'),
onTap: () => _alertOnListTileTap(context),
),
Divider(),
...
],
),
),
);
}
_alertOnListTileTap(BuildContext context) {
Navigator.of(context).pop();
showDialog(
context: context,
child: AlertDialog(
title: const Text('Not Implemented'),
actions: <Widget>[
FlatButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
);
}
}
Doing this without using bloc will make your code difficult to manage as it scales unless you just need an app prototype without any business logic.
Nonetheless, you can do it without bloc as follows;
Place all you screen in the body: as a list which displays the appropriate screen by indexing. like
body: [
Expenses(),
Inspiration()
Personal(),
Work(),
More(),
].elementAt(selectedIndex),
drawer: MdDrawer(onTap: (int val){
setState(() {
this._selectedIndex=val;
});
}
,)
Now you can push the desired body to display by providing the index as the return value of the Navigator.of(context).pop(index) or a callback function into MdDrawer. We will to do the callback function method. The index return will be used to update the state using setState.
class MdDrawer extends StatelessWidget {
final String title; final Function onTap;
MdDrawer({Key key, this.title, this.onTap}) : super(key: key);
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Text('MyPage'),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
UserAccountsDrawerHeader(
accountName: const Text(_AccountName),
accountEmail: const Text(_AccountEmail),
currentAccountPicture: CircleAvatar(
backgroundColor: Colors.brown,
child: Text(_AccountAbbr),
),
),
ListTile(
leading: Icon(Icons.lightbulb_outline),
title: Text('Notes'),
onTap: () => _alertOnListTileTap(context, 0),
),
ListTile(
leading: Icon(Icons.lightbulb_outline),
title: Text('Expenses'),
onTap: () => _alertOnListTileTap(context, 1),
),
Divider(),
...
],
),
),
);
}
_alertOnListTileTap(BuildContext context, int index ) {
onTap(indext);
Navigator.of(context).pop();
}
}
I hope this helps
Related
I want to write an ui as below:
the main feature is when click the button ,a new random position Text will be created inside the red box, the problem I faced is when I click the button ,a randon position Text widget will be create,but the old Text was gone, anyone can help me ? following is my code:
class AddNewWidget extends StatefulWidget {
const AddNewWidget({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() => _AddNewWidgetState();
}
class _AddNewWidgetState extends State<AddNewWidget> {
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: const Text("Add Text"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Add Text Below:'),
Stack(
children: [
Container(
width: double.infinity,
height: 600,
decoration: BoxDecoration(
border: Border.all(width: 2.0, color: Colors.red),
),
),
_addText(),
],
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _press,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
_press() {
//print("_press");
setState(() {});
}
_addText() {
return Positioned(
child: Text(
"hello ${Random().nextInt(10)}",
key: ValueKey(Random().nextInt(100)),
),
left: (Random().nextInt(300)).toDouble(),
top: (Random().nextInt(600)).toDouble(),
);`enter code here`
}
}
Create list to hold the generated item and then show the list on stack like
class AddNewWidget extends StatefulWidget {
const AddNewWidget({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() => _AddNewWidgetState();
}
class _AddNewWidgetState extends State<AddNewWidget> {
List<Widget> items = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Add Text"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Add Text Below:'),
Expanded(
child: Stack(
children: [
Container(
height: 600,
decoration: BoxDecoration(
border: Border.all(
width: 2.0,
color: Colors.red,
),
),
),
...items.map((e) => e).toList()
],
),
),
FloatingActionButton(
onPressed: _press,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _press,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
_press() {
items.add(_addText());
setState(() {});
}
Widget _addText() {
return Positioned(
child: Text(
"hello ${Random().nextInt(10)}",
key: ValueKey(Random().nextInt(100)),
),
left: (Random().nextInt(300)).toDouble(),
top: (Random().nextInt(600)).toDouble(),
);
}
}
include two fab, if you need to position any fab, place it within stack with Positioned(bottom:-20,righ:20), play with this value
This is my homepage.dart. The error here said that there is an unexpected null value. I've been trying to debug this for the day but i still could not manage to find it, how to solve this problem? When i try to run the code. It won't shows the data from the 'Parking' which is inside the firestore database. The data was indeed there but it wont show inside this page. Can anyone help me with this ?
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'addparking.dart';
class AdminHomePage extends StatefulWidget {
const AdminHomePage({Key? key}) : super(key: key);
#override
State<AdminHomePage> createState() => _AdminHomePageState();
}
class _AdminHomePageState extends State<AdminHomePage> {
CollectionReference ref = FirebaseFirestore.instance.collection('Parking');
//DELETE
Future<void> _deleteProduct(String productId) async {
await ref.doc(productId).delete();
// Show a snackbar
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('You have successfully deleted a product')));
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.lightBlueAccent,
appBar: AppBar(
backgroundColor: Color(0xFF121212),
elevation: 0.0,
title: const Text('Admin Page',
style:TextStyle(
color: Color(0xFFFFFFFF),
fontWeight: FontWeight.bold,
),
),
centerTitle:true,
),
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection('Parking').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if(snapshot.hasData){
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context,index){
final DocumentSnapshot documentSnapshot = (snapshot.data!.docs[index]);
return Card(
margin: const EdgeInsets.all(10),
child: ListTile(
title: Text(documentSnapshot['level']),
subtitle: Text(documentSnapshot['parking']),
trailing: Row(
children: [
IconButton(
icon: const Icon(Icons.edit),
onPressed: (){}
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () => _deleteProduct(documentSnapshot.id),
),
],
),
),
);
});
}
return const Center(
child: CircularProgressIndicator(),
);
},
),
drawer: const NavigationDrawer(),
);
}
}
class NavigationDrawer extends StatelessWidget {
const NavigationDrawer({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) => Drawer(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget> [
buildHeader(context),
buildMenuItems(context),
],
),
),
);
Widget buildHeader (BuildContext context) => Container(
color: Colors.amber,
child: InkWell(
onTap: (){},
child: Container(
padding: EdgeInsets.only(
top: 24 + MediaQuery.of(context).padding.top,
bottom: 24,
),
child: Column(
children: const [
CircleAvatar(
radius: 40,
backgroundImage: NetworkImage(
'https://www.shutterstock.com/image-vector/people-icon-vector-illustration-flat-design-405042562'
),
),
SizedBox(height: 12),
Text(
'Admin'
)
],
),
),
),
);
Widget buildMenuItems (BuildContext context) => Container(
padding: const EdgeInsets.all(24),
child: Wrap(
children: [
ListTile(
leading: const Icon(Icons.home_outlined),
title: const Text('Home'),
onTap:(){}
),
const Divider(color: Colors.black54,),
ListTile(
leading: const Icon(Icons.home_outlined),
title: const Text('Add Parking'),
onTap:(){
Navigator.pop(context);
Navigator.of(context).push(MaterialPageRoute(builder: (context) => AddParking(),));
}
),
const Divider(color: Colors.black54,),
ListTile(
leading: const Icon(Icons.home_outlined),
title: const Text('Delete Parking'),
onTap:(){}
),
const Divider(color: Colors.black54,),
ListTile(
leading: const Icon(Icons.home_outlined),
title: const Text('Update Parking'),
onTap:(){}
),
const Divider(color: Colors.black54,),
ListTile(
leading: const Icon(Icons.home_outlined),
title: const Text('Report Feedback'),
onTap:(){}
),
const Divider(color: Colors.black54,),
ListTile(
leading: const Icon(Icons.home_outlined),
title: const Text('Payment Setup'),
onTap:(){}
),
],
),
);
}
try
1- documentSnapshot?['level']
2- documentSnapshot?['parking']
It's really hard to track down the error without the stacktrace but you can try to change the following lines:
Text(documentSnapshot['level'] ?? "")
Text(documentSnapshot['parking'] ?? "")
Text() requires a string as a parameter that isn't null and documentSnapshot['level'] returns an nullable value because the key level might not exist. Same for parking.
Is it possible for me to open a page with icons when I click on the place I drew in red in the picture, like the bottomnavbar on Instagram, but I want mine to be like in the picture
What you have to do is:
add a drawer to your scaffold
add a GlobalKey to your Widget which you will use to open the Drawer
Remove the AppBar Menu button if you don't want it there
Add a the button and Position it in your body
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
final appTitle = 'Drawer Demo';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: appTitle,
home: MyHomePage(title: appTitle),
);
}
}
class MyHomePage extends StatelessWidget {
final String title;
//Add GlobalKey which you will use to open the drawer
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
MyHomePage({Key? key, required this.title}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
//Set GlobalKey
key: _scaffoldKey,
appBar: AppBar(title: Text(title),
//This will remove the AppBar menu button
automaticallyImplyLeading: false,),
body:
Center(child:
Container(
width: double.infinity,
alignment: Alignment.centerLeft,
child: InkWell(
//This function will open the Side Menu
onTap: ()=> _scaffoldKey.currentState?.openDrawer()
,
child: Icon(
Icons.menu,
size: 20,
),
),
),
),
//Add Drawer to your Scaffold
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
decoration: BoxDecoration(
color: Colors.blue,
),
child: Text('Drawer Header'),
),
ListTile(
title: Text('Item 1'),
onTap: () {
Navigator.pop(context);
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
Navigator.pop(context);
},
),
],
),
),
);
}
}
I have a bottom navigation bar, that lets me navigate between pages, while keeping the Bottom Navigation bar in place (Using Persistent Bottom Navigation bar package)
I also want to have a extra navigation button, that sends me to another page not listed on the Bottom Navigation bar, but all the different ways I have tried, it pushes me to another page, that is not inside the wrapper.
How could I navigate to another page from AppBar (Page is not listed on the bottom navigation bar) without losing the Navigation bar?
Attatching wrapper code
class Wrapper extends StatefulWidget {
final BuildContext menuScreenContext;
Wrapper({Key key, this.menuScreenContext}) : super(key: key);
#override
_WrapperState createState() => _WrapperState();
}
class _WrapperState extends State<Wrapper> {
final AuthService _auth = AuthService();
PersistentTabController _controller;
bool _hideNavBar;
#override
void initState() {
super.initState();
_controller = PersistentTabController(initialIndex: 0);
_hideNavBar = false;
}
List<Widget> _buildScreens() {
return [
HomePage(
hideStatus:_hideNavBar,
),
Page1(),
Page2(),
Page3(),
Page4(
hideStatus:_hideNavBar,
),
];
}
List<PersistentBottomNavBarItem> _navBarsItems() {
return [
PersistentBottomNavBarItem(
icon: Icon(Icons.home),
title: "Home",
activeColor: Colors.blue,
inactiveColor: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.search),
title: ("Search"),
activeColor: Colors.teal,
inactiveColor: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.add),
title: ("Add"),
activeColor: Colors.deepOrange,
inactiveColor: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.settings),
title: ("Settings"),
activeColor: Colors.indigo,
inactiveColor: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.settings),
title: ("Settings"),
activeColor: Colors.indigo,
inactiveColor: Colors.grey,
),
];
}
#override
Widget build(BuildContext context)
{
final user = Provider.of<NUser>(context);
if(user==null){
return Authenticate();}
else {
return Scaffold
(
drawer: Drawer(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>
[
TextButton
(child:Text('hey'), onPressed: ()
{
pushNewScreenWithRouteSettings(
context,
settings: RouteSettings(name:'/home'),
screen: HomePage());
}
),
ElevatedButton.icon(
onPressed: () async {await _auth.signOut();},
icon: Icon(Icons.person),
label: Text('Logout'),
),
],
),
),
),
appBar: AppBar(
actions: [
IconButton(iconSize: 150,icon: Image.asset("assets/BUTTON.png", color: Colors.black,height: 1000,width: 1000,), onPressed: ()
{
Navigator.push(context, MaterialPageRoute(builder: (context) => Profile()));
}),
ButtonTheme(
minWidth: 100.0,
height: 100.0,
child: TextButton(
onPressed: () {},
child: Text(" 4444 "),
),
),
],
),
body: PersistentTabView.custom
(
context,
controller: _controller,
screens: _buildScreens(),
confineInSafeArea: true,
itemCount: 5,
handleAndroidBackButtonPress: true,
resizeToAvoidBottomInset: false,
stateManagement: true,
hideNavigationBar: _hideNavBar,
screenTransitionAnimation: ScreenTransitionAnimation(
animateTabTransition: true,
curve: Curves.ease,
duration: Duration(milliseconds: 200),
),
customWidget: CustomNavBarWidget
(
items: _navBarsItems(),
onItemSelected: (index) {
setState(() {
_controller.index = index; // THIS IS CRITICAL!! Don't miss it!
});
},
selectedIndex: _controller.index,
),
),
);
}
}
}
class Profile extends StatefulWidget {
Profile({Key key}): super(key: key);
#override
_ProfileState createState() => _ProfileState();
}
class _ProfileState extends State<Profile> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title:Text('sample'),
),
);
}
}
I tried creating a class for the page in wrapper, but no luck. Other pages are individual files. I am trying to navigate with the AppBar Button
So I've looked several places for how this is supposed to be implemented and I'm sure I'm missing something trivial, but I have a flutter app with a Scaffold who's body is a PageView. I need to have a different FAB for some pages and the way it's currently set up is the floatingActionButton attribute of the scaffold is set to access an array of FloatingActionButtons with the index being the _currentPageIndex (private variable shared by bottomNavBar and _pageController.
This changes the FAB abruptly which is not the desired behavior.
I'm trying to get the FAB to animate (scale out and scale back) in when the page changes like in the material spec:
Tabbed Screens
When tabs are present, the FAB should briefly disappear, then >reappear when the new content moves into place. This expresses >that the FAB is not connected to any particular tab.
I would appreciate any advice on how to go about implementing it simply (I'm pretty sure I'm missing something trivial). The alternative is to manually animate in and out FABs myself by wrapping it in something.
You could try using AnimatedCrossFade Widget something like this :
class TestingNewWidgetState extends State<TestingNewWidget> {
int currentIndex = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: AnimatedCrossFade(
crossFadeState: currentIndex == 0
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: Duration(seconds: 1),
firstChild: FloatingActionButton(
onPressed: () => null,
child: Icon(Icons.arrow_left),
backgroundColor: Colors.red,
),
secondChild: FloatingActionButton(
onPressed: () => null,
child: Icon(Icons.arrow_right),
backgroundColor: Colors.blue,
),
),
body: PageView(
onPageChanged: (index) {
setState(() {
currentIndex = index;
});
},
children: <Widget>[
Scaffold(
body: Center(
child: Text("page 1"),
),
),
Scaffold(
body: Center(
child: Text("page 2"),
),
),
],
),
);
}
}
UPDATE
Remember you can create your own widget, this is an example using a custom FloatingActionButton:
class TestingNewWidgetState extends State<TestingNewWidget> {
int currentIndex = 0;
#override
Widget build(BuildContext context) {
var customFabButton;
if (currentIndex == 0) {
customFabButton = CustomFabButton(
color: Colors.red,
onPressed: () => null,
icon: Icons.alarm,
);
} else if (currentIndex == 1) {
customFabButton = CustomFabButton(
color: Colors.blue,
onPressed: () => null,
icon: Icons.satellite,
);
} else {
customFabButton = CustomFabButton(
color: Colors.green,
onPressed: () => null,
icon: Icons.verified_user,
);
}
return Scaffold(
floatingActionButton: customFabButton,
body: PageView(
onPageChanged: (index) {
setState(() {
currentIndex = index;
});
},
children: <Widget>[
Scaffold(
body: Center(
child: Text("page 1"),
),
),
Scaffold(
body: Center(
child: Text("page 2"),
),
),
Scaffold(
body: Center(
child: Text("page 3"),
),
),
],
),
);
}
}
class CustomFabButton extends StatelessWidget {
final IconData icon;
final Color color;
final VoidCallback onPressed;
const CustomFabButton({Key key, this.icon, this.color, this.onPressed})
: super(key: key);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPressed,
child: AnimatedContainer(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: color,
),
duration: Duration(seconds: 1),
height: 50.0,
width: 50.0,
child: Icon(icon),
),
);
}
}