I have a problem with my flutter project, I create button to display dialog with form and textfield, when dialog is open then I tap texfield, page is recreate, this is my code
void _showDialog(){
showDialog(
context: context,
builder: (BuildContext context) {
return CupertinoAlertDialog(
title: Text('Add New'),
content: Card(
color: Colors.transparent,
elevation: 0.0,
child: Column(
children: <Widget>[
TextField(
decoration: InputDecoration(
labelText: "Item",
filled: true,
fillColor: Colors.grey.shade50),
),
],
),
),
);
},
);
}
how I can solve it? thank you so much for your help
Mmm, from your code nothing looks weird... maybe you should share the entire class, or your business logic from another part of the tree (like a stream that rebuilds your view )...
I did a basic test in the Simulator and works fine.
But now I figure you are using a StatefulWidget, cause you have access to the context, so many some other code is doing setState().
Opening or closing the keyboard by pressing on a TextField rebuilds the Scaffold or whichever material is used to wrap your screen. This is normal behavior.
By 'recreating the page' do you mean that it loses its state? (it loses the values for data like if you use hot-restart instead of hot-reload), if so then this is not the standard behavior and we may need more information on your page/code to figure this out.
Related
I created a form that once submitted shows a dialog to the user, like this:
.....
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return AlertDialog(
contentPadding: EdgeInsets.all(0),
content: Container(
child: Wrap(
children: [
Container(
width: double.infinity,
margin: EdgeInsets.all(0),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(gradient: linearGradientCustom),
child: Column(
children: [
.....
I am not using any button or icon to close the dialog, since the dialog box is quite small and it just makes sense to simply tap away from it to dismiss it.
The issue is that I need to redirect the users to a different route on dismiss, instead of simply popping the dialog context.
How can I achieve this?
Thanks a lot.
You can use .then like this
await showDialog(
....//Your Dialog Code
).then((val){
// reditect to specific route
});
There seem to be many questions regarding this error but I'm yet to find an answer that will work in my situation.
The behaviour I'm seeing is that the Dismissible works, it fires and deletes the item, but for a moment it shows an error in the ListView. I'm guessing it's waiting for the tree to update based on the Stream<List>, which in turn is removing the record from Firebase.
My StreamBuilder...
return StreamBuilder<List<Person>>(
stream: personBloc.personsByUserId(userId),
builder: (context, snapshot) {
...
}
My ListView.builder()
ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
var person = snapshot.data[index];
return GestureDetector(
onTap: () {
Navigator.of(context)
.pushNamed('/reading/${person.personId}');
},
child: Dismissible(
key: Key(person.personId),
direction: DismissDirection.endToStart,
onDismissed: (direction) {
personBloc.deletePerson(person.personId);
},
background: Container(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Icon(
FontAwesomeIcons.trash,
color: Colors.white,
),
Text(
'Delete',
style: TextStyle(color: Colors.white),
textAlign: TextAlign.right,
),
],
),
),
color: Colors.red,
),
child: AppCard(
//Bunch of properties get set here
),
),
);
},
My deletePerson
deletePerson(String personId) async {
fetchPersonId(personId).then((value) {
if (value.imageUrl.isNotEmpty) {
removeImage();
}
db.deletePerson(personId);
});
}
I've tried changing the onDismissed to a confirmDismiss with no luck.
Any suggestions?
This happens when you dismiss with a Dismissible widget but haven't removed the item from the list being used by the ListView.builder. If your list was being stored locally, with latency not being an issue, you might never see this issue, but because you are using Firestore (I assume, based on your mention ofFirebase) then there is going to be some latency between asking the item to be removed from the DB and the list getting updated on the app. To avoid this issue, you can manage the local list separately from the list coming from the Stream. Updating the state as the stream changes, but allowing you to delete items locally from the local list and avoiding these kind of view errors.
I ended up making a couple of changes to my code to address this.
I added a BehaviourSubject in my bloc to monitor whether the delete was taking place or not. At the beginning of the firestore delete I set this to true and then added a .then to the delete to set it back to false.
I then added a Streambuilder around the ListView on the screen to monitor the value of this and show a CircularProgressIndicator when true.
It now looks like this:
Thanks for your help.
I'm using Rubber library at the moment, do you know an approach without using 3rd parts libraries?
The Bottom Sheet must be persistent (not dismissable, not triggered by any button instead, always displayed) and draggable (It must be expanded and collapsed by dragging gestures)
Perhaps DraggableScrollableSheet could work?
I haven't yet tried it out myself, but maybe you could fiddle with a listview to make it work.
I'm guessing something like having it's child be a listview, and then limit both the max child size and the maximum scroll extent
If you do not care that the bottom sheet must snap to different positions you can use the widget from the following package (snapping_sheet) I made.
Or, if you do not want to use it as a 3rd part library, you can copy the code and use it as your own widget from repository here: Github - Snapping sheet
Use DraggableScrollableSheet. Here's an example:
Stack(
children: [
Container(), //the page under the DraggableScrollableSheet goes here
Container(
height: MediaQuery.of(context).size.height,
child: DraggableScrollableSheet(
builder: (BuildContext context, myscrollController) {
return Container(
color: Colors.blue,
child: ListView.builder(
controller: myscrollController,
itemCount: 40,
itemBuilder:(BuildContext context, int index) {
return ListTile(title: Text('Item $index',
style: TextStyle(color: Colors.black),
));
},
),
);
},
),
),
],),
I hope I can make this kind of pop-up effect similar to dropDownMenuButton. Is there any plugin or example that can be used for reference or help?
If you want a floating window i would suggest using a dialog.
To use a dialog you use a function and provide it with a context
This example should show a rounded corned white dialog with "YAY!" in the middle of it.
You close the dialog calling Navigator.of(context).pop() , and You could also use the align widget combined with padding to make it appear to the bottom, top, left, and right.
Touching on the backdrop of the dialog will also dismiss it.
void _showDialog(context) {
showDialog(
context: context,
builder: (BuildContext context) {
// return my custom widgets
return Center(
child: SizedBox(
width: 250.0,
height: 250.0,
child: Material( //Use material to use FlatButton, IconButton, InkWell, etc.
borderRadius: BorderRadius.all(Radius.circular(12.0)),
color: Colors.white,
child: Text('YAY!')
)));
},
);
}
Feel free to experiment.
This is my code:
build(BuildContext context) {
return new Scaffold(
body: new SafeArea(
child: new ListView.builder(
itemBuilder: (itemBuilder),
itemCount: (1),
padding: kMaterialListPadding,
),
)
);
}
itemBuilder(BuildContext context, int index) {
return new TextFormField(
decoration: new InputDecoration(
border: const OutlineInputBorder(),
hintText: "What's on your mind?",
helperText: "5-500 characters",
),
maxLines: 3,
);
}
When I tap on the text field, keyboard opens but lot of blank space appears on top of keyboard as you can see in the picture (border of textfield is cut).
It happens because of the ListView. If I add just the text field to the body, appearance is fine.
The reason for lot of wasted space was because there was a Scaffold inside a Scaffold. Each scaffold adding space for keyboard. Removing one solved the problem.
Scaffold has a property resizeToAvoidBottomPadding.
Set this property false
For those who see white space after closing the keyboard, it can be caused by MediaQuery, where in my case I used MediaQuery around the base scaffold to fix the problem of using RangeSlider inside a drawer(using the RangeSlider will show the behavior of closing the drawer not changing the value of the slider ), where I used this:
MediaQuery(
data: MediaQueryData.fromWindow(window).copyWith(
gestureSettings: const DeviceGestureSettings(touchSlop: kTouchSlop)),
child: Scaffold(...)
But this however causes the white space that we saw after dismissing the keyboard, also it causes that when you open the keyboard on form, the screen won't scroll anymore.
So I add the media query solution only on the Scaffold where I used the drawer...
FYI, for those who uses Getx, I used it with bottom app bar, where we use:
Scaffold(
body: Obx(
() => IndexedStack(
children: controller.menuPages,
index: controller.navMenuIndex(),
),
),
and then after the main tabs, you use another Scaffold (I used the MediaQuery on this one )