How do I programmatically open and close drawer using keys in Flutter? - flutter

I am looking to open and close a drawer programmatically when I press on an icon. I am trying to use keys, but I am not having much luck. I found this article - Flutter: How to open Drawer programmatically ,but I am having issues.
I have a column of icons (see screenshot) that I include in one file and my drawer is in another, both of which are obviously included in a third (which is a fullscreen google map). I am looking at using a global key, but I am unsure where to put everything.
In my map page I have
class _TheMapState extends State<TheMap> with WidgetsBindingObserver {
GlobalKey<ScaffoldState> _drawerKey = GlobalKey();
...
...
When I try to add the key in my drawer page, it doesn't recognise it, so I add the GlobalKey line to my drawer page. I also have to do that to my icon options page too, otherwise the app won't build, due to the errors. There are no errors when I do this, but nothing happens when I click on the button.
Here is where I added the key to the drawer.
Widget mapDrawer() {
return Drawer(
key: _drawerKey,
...
...
Here is my icon code, which is in a separate file.
Widget _buildShowHideDrawerIcon() {
return Container(
child: Opacity(
opacity: 0.60,
child: Container(
padding: EdgeInsets.all(7.0),
decoration: BoxDecoration(
color: Colors.white,
//border: Border.all(color: Colors.black12, width: 1.0),
boxShadow: [
BoxShadow(
color: Colors.black,
offset: Offset(0.0, 0.0),
blurRadius: 3.0,
),
],
),
child: InkWell(
onTap: () {
print("SHOW/HIDE DRAWER ICON PRESSED");
setState(() {
_drawerKey.currentState.openDrawer();
});
},
child: Icon(
Icons.swap_horiz,
color: Colors.black87,
size: 24.0,
semanticLabel: 'Show ,or hide sliding drawer',
),
),
),
),
);
}
I would appreciate any help on this.

Assign the key to Scaffold, not Drawer
Scaffold(
key: _drawerKey,
drawer: Drawer(),

You should assign the key to Scaffold, not Drawer
Scaffold(
key: _drawerKey,
And replace the line:
_drawerKey.currentState.openDrawer();
With
_drawerKey.currentState?.openDrawer();

Related

How to close flutter speed dial when tap on a label widget?

Is there a way to close the flutter speedDial when tap on a label widget?. I did not use SpeedDial's child property, but it has that feature. Currently when I tap on a label widget it stays until I manually close the widget. Or even a way to change the child property of SpeedDial widget would be enough, while I want a custom shape like in the picture.
Navigator.pop() did not work
SpeedDial(
buttonSize: const Size(45, 45),
animatedIcon: AnimatedIcons.menu_close,
children: [
SpeedDialChild(
labelWidget: GestureDetector(
onTap: () async {
Feedback.forTap(context);
await _crudStorage.deleteAllTask();
},
child: Container(
height: 50.0,
decoration: BoxDecoration(
color:
Theme.of(context).cardColor,
border: Border.all(width: 2.0),
borderRadius:
BorderRadius.circular(30.0),
),
child: Row(
children: [
const Padding(
padding: EdgeInsets.only(
left: 12.0, right: 8.0),
child:
Text('Clear all tasks'),
),
Padding(
padding:
const EdgeInsets.only(
right: 8.0),
child: SvgPicture.asset(
'assets/svg/all.svg',
),
),
],
),
),
),
),
],
)
don't use async & await on tap use separate function to Call
https://tutorialmeta.com/question/how-to-call-async-function-with-ontap-flutter
refer the above link
It was so simple. Also the development team, provided how to implement this on their official extension page on pub.dev go to pub. I will mention the same documentation for your reference:
first you need to create a value notifier:
ValueNotifier<bool> isDialOpen = ValueNotifier(false);
Then set openCloseDial to isDialOpen in your SpeedDial:
SpeedDial(
...
openCloseDial: isDialOpen,
...
)
Now you can change the state of dial open:
isDialOpen.value = false;
Example: Just set the value to false inside the onTap callback :)
onTap: () async {
Feedback.forTap(context);
await _crudStorage.deleteAllTask();
isDialOpen.value = false;
},
use closeManually: false in SpeedDial Contructor. The widget will close automatically on select any function.

Searching for the name of a specific menu - Flutter

So I'm searching for a Menu often found in a Settings Screen. It's used to select a Setting.
It opens when you press on a ListTile and then it fills the mayority of the Screen, while the borders are transparent. In the menu you have to select one of the options.
An example usecase of that would be to select a Language(onTap of the ListTile opens a Menu where you can select between all the avaliable languages)
It is similar to that of a PopupMenuButton, however as already mentioned it fills most of the screen, and the individual selectable items have a radiobutton in front of the text(probably RadioListTiles)
I hope someone gets what I'm talking about, because for the past 3 hours I'm searching for this widget but just find articles about the PopupMenuButton over and over.
Edit: I finally found an app that uses the feature I'm looking for
: https://imgur.com/a/A9k71io
By clicking on the first ListTile in the first Picture, the dialog in the second picture opens up.
Hopefully this custom widget is something roughly what you want, try to copy and paste it in your project and play with it.
this is made using the Dialog widget, to exit the Dialog you can tap out of it/ press the device back arrow and I added a small back icon on the top left corner.
tell me if it helped :)
class TestPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;// the device size
return Scaffold(
body: Center(
child: ListTile(
tileColor: Colors.grey[300],
title: Text(
'Language',
style: TextStyle(fontSize: 25),
),
onTap: () => showDialog(
context: context,
builder: (context) => Dialog(
insetPadding: EdgeInsets.all(20),
child: Container(
color: Colors.white,
height: deviceSize.height,
width: deviceSize.width,
child: Column(
children: [
Row(
children: [
IconButton(
color: Colors.red,
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.of(context).pop(),
),
],
),
Spacer(),
Text('Pick A Language'),
Spacer(),
],
),
),
),
),
),
),
);
}
}

Flutter RaisedButton Hightlightelevation delay

I have created the following RaisedButton in Flutter:
The problem is, the button's highlightElevation triggers when you press and hold the button for approximately 1 second when I have the image shown on the left of it, but when I remove the image, it works as intended.
Is there a way to fix this while keeping the image?
here is my code:
Widget systems(String systemName, String systemTitle, Image img) {
return Center(child:
Container( width:width-20,height:110,child:
Column( children: <Widget>[
SizedBox(height: 10),
RaisedButton( elevation: 10,splashColor: Colors.transparent,highlightElevation: 0, shape:
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
),
color: Colors.white,
onPressed: () {},
child: Padding(
padding: EdgeInsets.only(left:0,top:15,bottom:15),
child: Row(children: [
img,Container(width:width-120,child:
Align(
alignment: Alignment.center,
child: Column(
children: [
Text(systemName, style: TextStyle(fontSize: 18)),
],
),
),)
])))
])));
}
PS: I have called this widget 9 times within a for loop in another widget, and when I reduce the number of the loop to 5 or lower, the button works as intended as well.
According to Flutter SDK highlightElevation is for the button's Material when the button is enabled and pressed.
Please refer https://api.flutter.dev/flutter/material/RawMaterialButton/highlightElevation.html
highlightElevation property :
The elevation for the button's Material when the button is enabled and pressed.

Hitting done on keyboard clears the text in flutter

I have a TextField() and, a controller, which I'm passing it to the TextField controller. My problem is that every time I hit done in my keyboard it clears my text.
I have followed this question: Flutter keyboard done button causes textfield content to vanish
question to solve my problem but nothing is working out for me. I'm clueless hence putting this question again on the StackOverflow.
MY CODE:
class ReferralPage extends StatelessWidget {
final TextEditingController controller = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
margin: EdgeInsets.only(top: 40.0, left: 16.0, right: 16.0),
child: Card(
color: Colors.white,
child: Padding(
padding: EdgeInsets.all(24.0),
child: TextField(
controller: controller,
cursorColor: Theme.of(context).primaryColor,
decoration: InputDecoration(hintText: 'Referral Code'),
)
)
),
decoration: BoxDecoration(boxShadow: [
new BoxShadow(color: Color.fromRGBO(173, 179, 191, 0.3), blurRadius: 20.0, offset: new Offset(0, 12))
])
)
);
}
}
As you can see my TextEditingController() is not inside the Widget build so there is no sense of happening that.
The only solution I found to this problem was to remove the controller but I don't want to do this, I want to use my controller for other purposes. I don't know why this is happening.
Any help would be appreciated. Thanks :)
You are having this issue because you are making use of a stateless widget. Change your stateless widget to a stateful widget so that your controller won't get rebuilt.

How do I remove Flutter IconButton big padding?

I want to have a row of IconButtons, all next to each other, but there seems to be pretty big padding between the actual icon, and the IconButton limits. I've already set the padding on the button to 0.
This is my component, pretty straightforward:
class ActionButtons extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.lightBlue,
margin: const EdgeInsets.all(0.0),
padding: const EdgeInsets.all(0.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
IconButton(
icon: new Icon(ScanrIcons.reg),
alignment: Alignment.center,
padding: new EdgeInsets.all(0.0),
onPressed: () {},
),
IconButton(
icon: new Icon(Icons.volume_up),
alignment: Alignment.center,
padding: new EdgeInsets.all(0.0),
onPressed: () {},
)
],
),
);
}
}
I want to get rid of most of the light blue space, have my icons start earlier on the left, and closer to each other, but I can't find the way to resize the IconButton itself.
I'm almost sure this space is taken by the button itself, 'cause if I change their alignments to centerRight and centerLeft they look like this:
Making the actual icons smaller doesn't help either, the button is still big:
thanks for the help
Simply pass an empty BoxConstrains to the constraints property and a padding of zero.
IconButton(
padding: EdgeInsets.zero,
constraints: BoxConstraints(),
)
You have to pass the empty constrains because, by default, the IconButton widget assumes a minimum size of 48px.
Two ways to workaround this issue.
Still Use IconButton
Wrap the IconButton inside a Container which has a width.
For example:
Container(
padding: const EdgeInsets.all(0.0),
width: 30.0, // you can adjust the width as you need
child: IconButton(
),
),
Use GestureDetector instead of IconButton
You can also use GestureDetector instead of IconButton, recommended by Shyju Madathil.
GestureDetector( onTap: () {}, child: Icon(Icons.volume_up) )
It's not so much that there's a padding there. IconButton is a Material Design widget which follows the spec that tappable objects need to be at least 48px on each side. You can click into the IconButton implementation from any IDEs.
You can also semi-trivially take the icon_button.dart source-code and make your own IconButton that doesn't follow the Material Design specs since the whole file is just composing other widgets and is just 200 lines that are mostly comments.
Wrapping the IconButton in a container simply wont work, instead use ClipRRect and add a material Widget with an Inkwell, just make sure to give the ClipRRect widget enough border Radius 😉.
ClipRRect(
borderRadius: BorderRadius.circular(50),
child : Material(
child : InkWell(
child : Padding(
padding : const EdgeInsets.all(5),
child : Icon(
Icons.favorite_border,
),
),
onTap : () {},
),
),
)
Instead of removing a padding around an IconButton you could simply use an Icon and wrap it with a GestureDetector or InkWell as
GestureDetector(
ontap:(){}
child:Icon(...)
);
Incase you want the ripple/Ink splash effect as the IconButton provides on click wrap it with an InkWell
InkWell(
splashColor: Colors.red,
child:Icon(...)
ontap:(){}
)
though the Ink thrown on the Icon in second approach wont be so accurate as for the IconButton, you may need to do some custom implementation for that.
Here's a solution to get rid of any extra padding, using InkWell in place of IconButton:
Widget backButtonContainer = InkWell(
child: Container(
child: const Icon(
Icons.arrow_upward,
color: Colors.white,
size: 35.0,
),
),
onTap: () {
Navigator.of(_context).pop();
});
I was facing a similar issue trying to render an Icon at the location the user touches the screen. Unfortunately, the Icon class wraps your chosen icon in a SizedBox.
Reading a little of the Icon class source it turns out that each Icon can be treated as text:
Widget iconWidget = RichText(
overflow: TextOverflow.visible,
textDirection: textDirection,
text: TextSpan(
text: String.fromCharCode(icon.codePoint),
style: TextStyle(
inherit: false,
color: iconColor,
fontSize: iconSize,
fontFamily: icon.fontFamily,
package: icon.fontPackage,
),
),
);
So, for instance, if I want to render Icons.details to indicate where my user just pointed, without any margin, I can do something like this:
Widget _pointer = Text(
String.fromCharCode(Icons.details.codePoint),
style: TextStyle(
fontFamily: Icons.details.fontFamily,
package: Icons.details.fontPackage,
fontSize: 24.0,
color: Colors.black
),
);
Dart/Flutter source code is remarkably approachable, I highly recommend digging in a little!
A better solution is to use Transform.scale like this:
Transform.scale(
scale: 0.5, // set your value here
child: IconButton(icon: Icon(Icons.smartphone), onPressed: () {}),
)
You can use ListTile it gives you a default space between text and Icons that would fit your needs
ListTile(
leading: Icon(Icons.add), //Here Is The Icon You Want To Use
title: Text('GFG title',textScaleFactor: 1.5,), //Here Is The Text Also
trailing: Icon(Icons.done),
),
I like the following way:
InkWell(
borderRadius: BorderRadius.circular(50),
onTap: () {},
child: Container(
padding: const EdgeInsets.all(8),
child: const Icon(Icons.favorite, color: Colors.red),
),
),
enter image description here
To show splash effect (ripple), use InkResponse:
InkResponse(
Icon(Icons.volume_up),
onTap: ...,
)
If needed, change icons size or add padding:
InkResponse(
child: Padding(
padding: ...,
child: Icon(Icons.volume_up, size: ...),
),
onTap: ...,
)