Navigation drawer closed after opening a screen from it - flutter

I have implemented a Navigation Drawer in my app.
There I have included a column as menu with some options
Here you have a screenshot from the Navigation Drawer:
If I click on an option a new screen is opened
The isssue I need to solve is that when the user clicks on the back button of that screen, the app shows the default screen not the navigation drawer.
What should I do to go back to the navigation drawer when clicking on the back button?
EDIT
This is how am I calling each class to be opened from the Navigation Drawer:
void onItemPressed(BuildContext context, {required int index}){
Navigator.pop(context);
switch(index){
case 1:
Navigator.push(context, MaterialPageRoute(builder: (context) => const GestionUsuariosInternos()));
break;
case 2:
Navigator.push(context, MaterialPageRoute(builder: (context) => const GestionUsuariosExternos()));
break;
case 3:
Navigator.push(context, MaterialPageRoute(builder: (context) => const GestionUsuariosVisitantes()));
break;
case 4:
Navigator.push(context, MaterialPageRoute(builder: (context) => const GestionEmpresas()));
break;
case 8:
Navigator.push(context, MaterialPageRoute(builder: (context) => Mapa()));
break;
}
}
EDIT
This is the code from one of the pages that is opened from the navigation drawer
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class Mapa extends StatefulWidget {
#override
State<Mapa> createState() => MapaState();
}
class MapaState extends State<Mapa> {
Completer<GoogleMapController> _controller = Completer();
static const CameraPosition _kGooglePlex = CameraPosition(
target: LatLng(37.42796133580664, -122.085749655962),
zoom: 14.4746,
);
static final CameraPosition _kLake = CameraPosition(
bearing: 192.8334901395799,
target: LatLng(37.43296265331129, -122.08832357078792),
tilt: 59.440717697143555,
zoom: 19.151926040649414);
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(
color: Colors.black, //change your color here
),
title: Text("Sample"),
centerTitle: true,
),
body: GoogleMap(
mapType: MapType.hybrid,
initialCameraPosition: _kGooglePlex,
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
),
floatingActionButton: FloatingActionButton.extended(
onPressed: _goToTheLake,
label: Text('To the lake!'),
icon: Icon(Icons.directions_boat),
),
);
}
Future<void> _goToTheLake() async {
final GoogleMapController controller = await _controller.future;
controller.animateCamera(CameraUpdate.newCameraPosition(_kLake));
}
}

You can use something called WillPopScope widget for that,
you can perform any operation when pressed back button.
You should wrap you screens with this widget and should make Navigation drawer available to every screen.
https://api.flutter.dev/flutter/widgets/WillPopScope-class.html

You can use WillPopScope widget to handle backbutton press event.Wrap the the WillPopScope widget on root of the pages widget. like this
class Page1 extends StatelessWidget {
Page1({Key? key}) : super(key: key);
GlobalKey<ScaffoldState> _globalkey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
_globalkey.currentState?.openDrawer();
// Scaffold.of(context).openDrawer();
return Future.value(false);
},
child: new Scaffold(
key: _globalkey,
drawer: Drawers.getDrawer(context),
appBar: AppBar(
iconTheme: IconThemeData(
color: Colors.black, //change your color here
),
title: Text("Pag1"),
centerTitle: true,
),
body: Container(),
),
);
}
}
to open a drawer while press backbutton
_globalkey.currentState?.openDrawer();
_globalkey is scaffoldstate type Globalkey .you can declare it inside the widget page class or outside.
GlobalKey<ScaffoldState> _globalkey = new GlobalKey<ScaffoldState>();
Sample Code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MaterialApp(home: MYAppWithoutFlicker()));
}
class MYAppWithoutFlicker extends StatefulWidget {
MYAppWithoutFlicker({Key? key}) : super(key: key);
#override
State<MYAppWithoutFlicker> createState() => _MYAppWithoutFlickerState();
}
class Drawers {
static Widget getDrawer(BuildContext context) {
return Container(
width: 100,
child: Drawer(
child: ListView(
children: [
ListTile(
onTap: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => Mapa()));
},
title: Text(
"Pag1",
),
),
ListTile(
onTap: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => Page1()));
},
title: Text("Pag2"),
),
ListTile(
onTap: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => Page2()));
},
title: Text("Pag3"),
),
],
),
),
);
}
}
class _MYAppWithoutFlickerState extends State<MYAppWithoutFlicker> {
// var decode = (bytes, {allowUpscaling, cacheHeight, cacheWidth}) {
GlobalKey<ScaffoldState> _globalkey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
;
return Scaffold(
key: _globalkey,
appBar: AppBar(
title: Text("Home"),
),
drawer: Drawers.getDrawer(context),
body: ListView(
// mainAxisAlignment: MainAxisAlignment.center,
// crossAxisAlignment: CrossAxisAlignment.center,
// shrinkWrap: false,
children: [
...List.generate(
10,
(index) => Container(
height: 100,
child: Card(
child: Center(
child: Text(
index.toString(),
style: TextStyle(fontSize: 25),
)),
),
))
],
),
);
}
#override
void initState() {}
}
class Page1 extends StatelessWidget {
Page1({Key? key}) : super(key: key);
GlobalKey<ScaffoldState> _globalkey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
_globalkey.currentState?.openDrawer();
// Scaffold.of(context).openDrawer();
return Future.value(false);
},
child: new Scaffold(
key: _globalkey,
drawer: Drawers.getDrawer(context),
appBar: AppBar(
iconTheme: IconThemeData(
color: Colors.black, //change your color here
),
title: Text("Pag1"),
centerTitle: true,
),
body: Container(),
),
);
}
}
class Page2 extends StatelessWidget {
const Page2({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return new Scaffold(
// key: _globalkey,
drawer: Drawers.getDrawer(context),
appBar: AppBar(
iconTheme: IconThemeData(
color: Colors.black, //change your color here
),
title: Text("Pag2"),
centerTitle: true,
),
body: Container(),
);
}
}
class Mapa extends StatefulWidget {
#override
State<Mapa> createState() => MapaState();
}
GlobalKey<ScaffoldState> _globalkey = new GlobalKey<ScaffoldState>();
class MapaState extends State<Mapa> {
GlobalKey<ScaffoldState> _globalkey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return WillPopScope(
child: new Scaffold(
key: _globalkey,
drawer: Drawers.getDrawer(context),
appBar: AppBar(
iconTheme: IconThemeData(
color: Colors.black, //change your color here
),
title: Text("Sample"),
centerTitle: true,
),
body: Container(),
floatingActionButton: FloatingActionButton.extended(
onPressed: _goToTheLake,
label: Text('To the lake!'),
icon: Icon(Icons.directions_boat),
),
),
onWillPop: () {
_globalkey.currentState?.openDrawer();
// Scaffold.of(context).openDrawer();
return Future.value(false);
},
);
}
Future<void> _goToTheLake() async {}
}

Related

PopupMenuButton not able to change icon when clicked

I'm using the PopupMenuButton in flutter for a web based project and trying to change the popupmenubutton icon when it's clicked. So in its initial state it would show Icons.menu and when opened, it could would Icons.close and once clicked again revert back to Icons.menu.
I have tried onSelected which does not get called at all when clicked in an attempt to change the icon.
I have used an icon or a child IconButton per the docs and used onPressed to setState however that doesn't work either.
Currently the elevated button when clicked, does not show the dropdown menu, nor does it update the icon.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool menuClicked = true;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
PointerInterceptor(
intercepting: true,
child: PopupMenuButton<String>(
offset: const Offset(10.0, 50.0),
color: Colors.black,
child: ElevatedButton(
onPressed: () {
setState(() {
menuClicked = !menuClicked;
});
},
child: Icon((menuClicked = true)
? Icons.menu
: Icons.close),),
itemBuilder: (BuildContext context) =>
<PopupMenuEntry<String>>[
PopupMenuItem(
value: "close",
child: ListTile(
leading: Icon(Icons.close, color: Colors.white),
title: Text('Close',
style: TextStyle(color: Colors.white)),
onTap: () {
Navigator.pop(context);
}),
),
],
),
],
),
),
body: Center(
child: Text('test'),
),
);
}
}
Equal sign will be ==
Icon((menuClicked == true) ? Icons.menu : Icons.close),
or you can do
Icon(menuClicked ? Icons.menu : Icons.close),
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool menuClicked = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
GestureDetector(
behavior: HitTestBehavior.translucent,
onPanDown: (details) {
setState(() {
menuClicked = true;
});
},
child: PopupMenuButton<String>(
offset: const Offset(10.0, 50.0),
color: Colors.black,
onSelected: (value) {
setState(() {
menuClicked = false;
});
},
padding: EdgeInsets.zero,
onCanceled: () {
setState(() {
menuClicked = false;
});
},
child: Icon(menuClicked ? Icons.close : Icons.menu),
itemBuilder: (BuildContext context) => [
PopupMenuItem(
value: "close",
child: ListTile(
leading: Icon(Icons.close, color: Colors.white),
title: Text(
'Close',
style: TextStyle(color: Colors.white),
),
onTap: () {
Navigator.pop(context);
},
),
),
],
),
),
],
),
);
}
}

Flutter: Adding button shows up behind ListView, "duplicate child" error

I'm trying to add a button to navigate to another screen but I'm not sure how to get it on the bottom of my list instead of behind it. This is my current list:
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.teal[800],
appBar: AppBar(
title: Text(widget.title),
),
body: SafeArea(
child: ListView.builder(
itemCount: Type.samples.length,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return BoardingDetail(boarding: Type.samples[index]);
},
),
);
},
child: buildBoardingCard(Type.samples[index]),
);
},
),
),
);
}
And I think this is the code I want to add to navigate to a new screen, I got this code from https://docs.flutter.dev/cookbook/navigation/navigation-basics
child: ElevatedButton(
child: const Text('Open route'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SecondRoute()),
);
},
),
I tried to integrate the navigation button into my code but it says I have "duplicate child". What is the proper way to do this?
You have to nest the ListView and ElevatedButton in a SingleChildScrollView with a Column
You can try running this to see how it is implemented:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "ListView.builder",
theme: ThemeData(primarySwatch: Colors.green),
debugShowCheckedModeBanner: false,
home: const ListViewBuilder());
}
}
class ListViewBuilder extends StatelessWidget {
const ListViewBuilder({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("ListView.builder")),
body: SingleChildScrollView(
child: Column(
children: [
ListView.builder(
shrinkWrap: true,
itemCount: 8,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: const Icon(Icons.list),
trailing: const Text(
"GFG",
style: TextStyle(color: Colors.green, fontSize: 15),
),
title: Text("List item $index"));
},
),
ElevatedButton(
child: const Text('Open route'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SecondRoute()),
);
},
),
],
),
),
);
}
}
class SecondRoute extends StatelessWidget {
const SecondRoute({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Second Route'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
// Navigate back to first route when tapped.
},
child: const Text('Go back!'),
),
),
);
}
}

How to show alerts when using full_pdf_viewer

I am using flutter full_pdf_viewer package to view a pdf before saving. I have a save option which I would like to have a confirmation before saving. However, when I try to render the alert it does not show up. Currently, I have a workaround where I pop the PDFViewerScaffold before showing the alert however this is not the intended behavior. This is the code I currently have
class EditorPage extends StatefulWidget {
const EditorPage({
Key key,
}) : super(key: key);
#override
_EditorPageState createState() => _EditorPageState();
}
class _EditorPageState extends State<EditorPage> {
#override
Widget build(BuildContext context) {
final Map arguments = ModalRoute.of(context).settings.arguments as Map;
final pdfPath = arguments['pdfPath'];
return Scaffold(
body: PDFViewerScaffold(
appBar: AppBar(
title: Text("Document"),
actions: <Widget>[
InkWell(
child: Icon(Icons.save),
onTap: () {
Navigator.of(context).pop();
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
title: Text('Enter the title of your notice'),
content: Text('This is a test'),
actions: <Widget>[
FlatButton(
child: Text('Approve'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
});
},
),
],
),
path: pdfPath),
);
}
}
Try to add a key to your Scaffold:
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
And in your Scaffold:
return Scaffold(
key: _scaffoldKey,
This solve the problem here.

Flutter - Change appbar on longpress with Material

I am trying to do this kind of thing with Flutter :
https://storage.googleapis.com/spec-host-backup/mio-design%2Fassets%2F0B3T7oTWa3HiFcHBDaTlreHdVZGc%2Fitem-selection-selecting-items.mp4
var gestureTemp = GestureDetector(
onLongPress: (){
print('LONG PRESSED');
//CHANGE APPBAR
},
child: Padding(
padding: EdgeInsets.only(right:8),
child: Chip(
avatar: CircleAvatar(
backgroundColor: Colors.grey.shade800,
child: icon
),
label: Text(space.label, style: TextStyle(fontSize: 12, color:Colors.grey.shade800))
),
));
It detects the long press, but I don't know how to change my appbar...
Any ideas ?
EDIT: Here is what I do
var appBar1 = AppBar(...);
var appBar2 = AppBar(...);
var appBar = appBar1;
My appBar is displayed in my Scaffold.
On my GestureDetector :
onLongPress: (){
print('LONG PRESSED');
setState(() {
appBar = appBar2;
});
},
Welcome to StackOverflow!
The approach you described sounds quite right. Here is a standalone example so you can double check your code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(home: MyPage());
}
}
class MyPage extends StatefulWidget {
#override
_MyPageState createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
static final AppBar _defaultBar = AppBar(
title: Text('Inbox'),
leading: Icon(Icons.menu),
actions: <Widget>[Icon(Icons.search), Icon(Icons.more_vert)],
backgroundColor: Colors.black,
);
static final AppBar _selectBar = AppBar(
title: Text('1'),
leading: Icon(Icons.close),
actions: <Widget>[
Icon(Icons.flag),
Icon(Icons.delete),
Icon(Icons.more_vert)
],
backgroundColor: Colors.deepPurple,
);
AppBar _appBar = _defaultBar;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _appBar,
body: Center(
child: RaisedButton(
child: Text('Switch!'),
onPressed: () {
setState(() {
_appBar = _appBar == _defaultBar
? _selectBar
: _defaultBar;
});
},
),
),
);
}
}

How to send setState to Second Page in Flutter?

I have a basic question about send setState
to Second Page in the same class as this method like
_GoToNextPage(){
Navigator.of(context).push(MaterialPageRoute(builder: (context) {...})
}
The problem is when I change background color in second page it doesn't
change color in the same page But it changes the color of The prime home page.
This is the full code...
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
home: SetStateToSecondPage(),
));
class SetStateToSecondPage extends StatefulWidget {
#override
_SetStateToSecondPageState createState() => _SetStateToSecondPageState();
}
class _SetStateToSecondPageState extends State<SetStateToSecondPage> {
Color color = Colors.deepPurpleAccent;
bool Switch = false;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: color,
appBar: AppBar(
title: Text('setState to Second Page ?'),
elevation: 0.0,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
RaisedButton(
onPressed: () {
setState(() {
Switch = !Switch;
color = Switch ? Colors.white : Colors.green;
});
},
child: Text('Change Back GroundColor'),
),
RaisedButton(
onPressed: () {
_GoToNextPage(context);
},
child: Text('To Next Page..'),
),
],
),
),
);
}
//------------- This is second Page ----------//
_GoToNextPage(BuildContext context) {
return Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
backgroundColor: color,
body: Center(
child: RaisedButton(
onPressed: () {
setState(() {
color = Colors.red;
});
},
child: Text('Change Back GroundColor'),
),
),
);
}));
}
}
thanks
SetState is specific to the object you are in . and when you call it you notify the framework that the state has changed . so calling setState in _SetStateToSecondPageState will not affect Second Page so you need to create another StatefulWidget
class SecondPage extends StatefulWidget {
MaterialColor secondColor ;
SecondPage({this.secondColor});
#override
_SecondPageState createState() => new _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
backgroundColor: widget.secondColor,
body: Center(
child: RaisedButton(
onPressed: () {
setState(() {
widget.secondColor = Colors.amber;
});
},
child: Text('Change Back GroundColor'),
),
),
);
}
}
and when you call _GoToNextPage use the SecondPage constructor to change the color
_GoToNextPage(BuildContext context) {
return Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return SecondPage(
);
}));
}