I have made customized Drawer and AppBar. I want the Drawer to be opened when action widget in the AppBar is tapped. I want to know how to implement this for the custom AppBar
#override
Widget build(BuildContext context) {
return Scaffold(
endDrawer:buildProfileDrawer(),
appBar: setAppBar(),
body: HomeBody()
);
}
//custom widget
Widget setAppBar(){
return AppBar(
actions: <Widget>[
IconButton(
icon: Icon(Icons.account_circle,),
onPressed: () {
//Open the drawer
},
)
],
);
}
//Custom drawer
buildProfileDrawer() {
return Drawer(
//....drawer childs
);
}
You should use GlobalKey in Scaffold, and call openEndDrawer method on it.
GlobalKey<ScaffoldState> _key = GlobalKey(); // add this
#override
Widget build(BuildContext context) {
return Scaffold(
key: _key, // set it here
endDrawer: buildProfileDrawer(),
appBar: setAppBar(),
body: Center(),
);
}
//custom widget
Widget setAppBar() {
return AppBar(
actions: <Widget>[
IconButton(
icon: Icon(Icons.account_circle),
onPressed: () {
_key.currentState.openEndDrawer(); // this opens drawer
},
)
],
);
}
//Custom drawer
buildProfileDrawer() {
return Drawer();
}
Update
GlobalKey<ScaffoldState> _key = GlobalKey();
#override
Widget build(BuildContext context) {
return Scaffold(
key: _key,
endDrawer: buildProfileDrawer(),
appBar: setAppBar(_key),
body: Center(),
);
}
Somewhere in some file.
Widget setAppBar(GlobalKey<ScaffoldState> globalKey) {
return AppBar(
actions: <Widget>[
IconButton(
icon: Icon(Icons.account_circle),
onPressed: () {
globalKey.currentState.openEndDrawer();
},
)
],
);
}
Somewhere in some other file
buildProfileDrawer() {
return Drawer();
}
You can use this in actions list:
StatefulBuilder(
builder: (BuildContext context, setState) {
return IconButton(
icon: Icon(Icons.format_align_right),
onPressed: () {
Scaffold.of(context).openEndDrawer();
},
);
},
),
We can use
Scaffold.of(context).openDrawer();
on onPressed inside an IconButton in your CustomAppBar or wherever you want to call the drawer.
In the Scaffold just ensure to provide the drawer: property a Drawer Widget.
Related
I've been trying flutter new declarative Navigator v2.0, following this
johnpryan example, I've decide to change FlatButton pop() in the BookDetailsScreen:
class BookDetailsScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
children: [
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Back'),
),
],
}
To the parent router AppBar() in the _AppShellState:
class _AppShellState extends State<AppShell> {
InnerRouterDelegate _routerDelegate;
ChildBackButtonDispatcher _backButtonDispatcher;
#override
Widget build(BuildContext context) {
var appState = widget.appState;
_backButtonDispatcher.takePriority();
return Scaffold(
appBar: appState.selectedBook != null
? AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => _routerDelegate.popRoute(),
),
actions: [
IconButton(
icon: Icon(Icons.more_vert),
onPressed: () => null,
)
],
)
: AppBar(),
body: Router(
routerDelegate: _routerDelegate,
backButtonDispatcher: _backButtonDispatcher,
),
Fullcode
My question is, I'm using _routerDelegate.popRoute() it's working, but I not sure if it is right way to do it?
PS: If someone have a more complex example using Navigator v2.0, I'm new to Flutter and need to know best practices to how separate and organize my code, how to add more routes for instance an Edit and login screen? working with more objects like users, books, authors and etc...
I have a tweak to show the back button, kinda naturally, when the BookDetailsScreen is presented.
In the _AppShellState class
#override
Widget build(BuildContext context) {
...
return Scaffold(
// <- Comment out this appBar
// appBar: AppBar(
// leading: appState.selectedBook != null
// ? IconButton(
// icon: Icon(Icons.arrow_back),
// onPressed: () => _routerDelegate.popRoute(),
// )
// : null,
// ),
...
// Keep the rest part the same
);
}
Add the appBar property into Screens Scaffold in the build method, like this below. Have the appBar on both BooksListScreen and BookDetailsScreen,
class BooksListScreen extends StatelessWidget {
...
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(), // <- This is the key
...
);
}
}
Hope this makes sense.
I have a todo app which has a listview with title and short summary showing when clicked on the listtile it should go to the particular todo details page which shows all the details regarding the todo
This is my listview
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: newdrawer(),
appBar: newappbar(),
body: _TaskList(),
floatingActionButton: FloatingActionButton(
foregroundColor: Colors.black54,
backgroundColor: Colors.blue,
elevation: 0,
child: Icon(Icons.add),
onPressed: () {
addDialog(context);
},
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
// ignore: non_constant_identifier_names
Widget _TaskList() {
if (Task != null) {
return FlatButton(
child: ListView.builder(
itemCount: Task.documents.length,
padding: EdgeInsets.all(5.0),
itemBuilder: (context, i) {
return new ListTile(
title: Text(Task.documents[i].data['Title']),
subtitle: Text(Task.documents[i].data['Summary']),
);
},
),
onPressed: () {},
);
} else {
return Text('Loading, Please wait..');
}
}
}
the on pressesd button of flat button which is empty in widget tasklist when clicked should open the detailtask page showing only that particular task details
class _taskdetailState extends State<taskdetail> {
//taskdetail([this.id]);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: newappbar(),
drawer: newdrawer(),
body: Column(
children: <Widget>[
Text('')
],
)
);
}
}
Please help me in my guess in my list view the on pressesd when tapped should take the document id and then it should pass on to the detail screen. But i am out of thoughts on how to do this.
in onPressed method, you need to pass the detail of Task
like this
onPressed: (){
navigator.push(context,MaterialPageRoute(builder:(context)=>_taskdetailState(details: Task.documents[i].data)));
}
now you can access this data like
class _taskdetailState extends State<taskdetail> {
final dynamic Taks;
_taskdetailState({this.Task});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title:Text(Task.Title)),
drawer: newdrawer(),
body: Column(
children: <Widget>[
Text('')
],
)
);
}
}
I would like to change the default Scaffold drawer icon (hamburger icon).
I tried to add a key to the Scaffold widget and a leading icon, but it didn't work form me:
GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
/* ... */
leading: IconButton(
icon: Icon(Icons.person),
onPressed: () {
_scaffoldKey.currentState.openDrawer();
},
),
),
drawer: Drawer(
/* ... */
),
/* ... */
);
}
}
How can I change the drawer icon?
I accomplished this by adding a leading icon wrapped by a Builder widget (the key was not needed):
return Scaffold(
appBar: AppBar(
/*...*/
leading: Builder(
builder: (BuildContext context) {
return IconButton(
icon: const Icon(Icons.person),
onPressed: () { Scaffold.of(context).openDrawer(); },
);
},
),
/*...*/
);
I want to open side drawer from a button exist in a container not from the AppBar side button. Also this should be open from right to left.
For more information I have added screenshot of my requirement
Here you have a basic sample:
#override
Widget build(BuildContext context) {
return Scaffold(
endDrawer: Drawer(),
appBar: AppBar(),
body: Builder(
builder: (context) {
return Center(
child: RaisedButton(
child: Text("open drawer"),
onPressed: () {
Scaffold.of(context).openEndDrawer();
},
),
);
},
),
);
}
Or you can use GlobalKey of ScaffoldState:
GlobalKey<ScaffoldState> _key = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return Scaffold(
key: _key,
endDrawer: Drawer(),
appBar: AppBar(),
body: Center(
child: RaisedButton(
child: Text("open drawer"),
onPressed: () {
_key.currentState.openEndDrawer();
},
),
),
);
}
}
Check this link for more information : https://api.flutter.dev/flutter/material/ScaffoldState/openEndDrawer.html
create a scaffold key then give it your scaffold widget
GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
then, to open drawer
_scaffoldKey.currentState.openDrawer()
or
_scaffoldKey.currentState.openEndDrawer()
If you create an Scafold there is an option for drawer. If you now create this drawer you get automaticly the menu icon on the leading position of the appbar. But i want an other icon there which opens the drawer. I tried to make an iconbutton myself on the leading position but this button can‘t open the drawer even with „Scafold.of(context).openDrawer()“ it can‘t open it.
Is there any option to replace the icon for the drawer button?
Use a Key in your Scaffold and show the drawer by calling myKey.currentState.openDrawer(), here is a working code:
import "package:flutter/material.dart";
class Test extends StatefulWidget {
#override
_TestState createState() => new _TestState();
}
class _TestState extends State<Test> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return new Scaffold(
key: _scaffoldKey,
drawer: new Drawer(),
appBar: new AppBar(
leading: new IconButton(
icon: new Icon(Icons.settings),
onPressed: () => _scaffoldKey.currentState.openDrawer(),
),
),
);
}
}
Alternative to the accepted answer which does not require a GlobalKey:
class _TestState extends State<Test> {
#override
Widget build(BuildContext context) {
return new Scaffold(
drawer: new Drawer(),
appBar: new AppBar(
leading: Builder(
builder: (context) => IconButton(
icon: new Icon(Icons.settings),
onPressed: () => Scaffold.of(context).openDrawer(),
),
),
),
);
}
}
Using GlobalKey:
final GlobalKey<ScaffoldState> _key = GlobalKey(); // Create a key
#override
Widget build(BuildContext context) {
return Scaffold(
key: _key, // Assign the key to Scaffold.
drawer: Drawer(),
floatingActionButton: FloatingActionButton(
onPressed: () => _key.currentState!.openDrawer(), // <-- Opens drawer
),
);
}
Using Builder:
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: Drawer(),
floatingActionButton: Builder(builder: (context) {
return FloatingActionButton(
onPressed: () => Scaffold.of(context).openDrawer(), // <-- Opens drawer.
);
}),
);
}
you need initialize scaffoldKey
after that,
Open drawer and close drawer
GestureDetector(
onTap: () {
if(scaffoldKey.currentState.isDrawerOpen){
scaffoldKey.currentState.openEndDrawer();
}else{
scaffoldKey.currentState.openDrawer();
}
},
child: LeadingIcon(icon: Icons.menu),//your button
),