Is it possible to push all content up when open keyboard? (not only textField area, whole page push up)
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return BottomSheet();
},
isScrollControlled: true);
BottomSheet class
class BottomSheet extends StatefulWidget {
#override
_BottomSheetState createState() => _BottomSheetState();
}
class _BottomSheetState extends State<BottomSheet> {
#override
Widget build(BuildContext context) {
return
SingleChildScrollView(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: Container(
child: Column(
children: <Widget>[...
I want to like this push-up,
But Current output is,
Simply putting reverse=true inside the SingleChildScrollView will suffice.
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
reverse: true,
child: Container(
........
........
You can simply give the widget a bottom position of MediaQuery.of(context).viewInsets.bottom if you are using a stack.
In your case, set margin : to MediaQuery.of(context).viewInsets.bottom instead of padding.
Wrap your whole widget inside a container and provide that container padding like this, it will work.
child: Container(
padding: EdgeInsets.only(
top: 25.0,
bottom: MediaQuery.of(context).viewInsets.bottom,
left: 25.0,
right: 25.0,
),
child: Form(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextFormField(
decoration: InputDecoration(
hintText: 'Email',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
keyboardType: TextInputType.emailAddress,
validator: (value) {
return _isEmailValid(value);
},
textInputAction: TextInputAction.next,
onSaved: (value) {},
controller: _emailController,
),
SizedBox(height: 10),
TextFormField(
obscureText: true,
decoration: InputDecoration(
hintText: 'Password',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
keyboardType: TextInputType.emailAddress,
validator: (value) {
return _isEmailValid(value);
},
textInputAction: TextInputAction.done,
onSaved: (value) {},
controller: _passwordController,
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {},
child: const Text('Forgot Password'),
),
],
),
ElevatedButton(
style: ElevatedButton.styleFrom(
side: const BorderSide(width: 1.3, color: Colors.white),
shadowColor: Colors.white,
),
onPressed: () {},
child: const Text('Login'),
),
TextButton(
onPressed: () {},
child: Text('Not have any Accoung? Sign Up'),
),
],
),
),
),
Set resizeToAvoidBottomInset property of the Scaffold as true.
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (BuildContext context) {
return Container(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: //your code
);
}
)
This works for me. Maybe try moving your padding inside the container.
Related
I have a text field widget that has an prefix icon . I want the prefix icon to be hidden when the text field is changed
my code:
TextField(
controller: messageInputController,
onChanged: (value){
messageInputChanged();
},
decoration: InputDecoration(
counterText: '',
prefixIcon: !showPrefixIcon ? Container() : Padding(
padding: const EdgeInsets.all(0),
child: IconButton(
onPressed: () {
imagePickerBottomSheet();
},
iconSize: 40,
color: Skin.gray,
icon: SvgPicture.asset(
'assets/svg/ic-image.svg',
height: 22,
color: Skin.gray,
)),
),
),
),
void messageInputChanged() {
if(messageInputController.text.isEmpty){
showPrefixIcon = true;
}else {
showPrefixIcon = false;
}
setState(() {});
}
But when the set state is called and the icon is hidden, the contents of the text field are also messed up
The InputDecorator accepts a Widget? for the prefixIcon, however, it does not work with a Container(). That's strange.
If I replace your
prefixIcon: !showPrefixIcon ? Container() : Padding(...)
with
prefixIcon: !showPrefixIcon ? SizedBox(height: 0.0, width: 0.0) : Padding(...)
it works.
I honestly don't know why.
updated proposal:
Use:
prefixIcon: !showPrefixIcon ? null : Padding(...)
And I just assume that you could then reasonably argue that this is ugly. Then, I fear, you have to change the way of doing it to something like this:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 70.0,
decoration: BoxDecoration(
border: Border.all(
color: Colors.blue,
),
borderRadius: const BorderRadius.all(Radius.circular(10))),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AnimatedSwitcher(
duration: const Duration(milliseconds: 600),
transitionBuilder: (child, animation) => SizeTransition(
sizeFactor: animation,
axis: Axis.horizontal,
child: child),
child: showPrefixIcon
? const Padding(
padding: EdgeInsets.all(8.0),
child: Icon(Icons.abc,
color: Colors.blue, size: 46),
)
: Container()),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: messageInputController,
decoration: const InputDecoration(
border: InputBorder.none,
hintText: 'enter text',
),
onChanged: (value) {
messageInputChanged();
},
),
),
),
],
),
),
),
),
);
}
}
I need 80 pixel top padding (so AppBar to be shown) for my bottom sheet when keyboard is visible and when keyboard is not visible.
This is my code:
import 'package:flutter/material.dart';
class Temp2Screen extends StatelessWidget {
const Temp2Screen({super.key});
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: MyWidget(),
),
);
}
}
class MyWidget extends StatefulWidget {
MyWidget({Key? key}) : super(key: key);
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
late ScrollController scrollController;
List<String> messages = [
"msg1", "msg2", "msg3", "msg4", "msg5", "msg6", "msg7", "msg8", "msg9", "msg10",
];
#override
void initState() {
super.initState();
scrollController = new ScrollController();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
showModalBottomSheet(
shape: const RoundedRectangleBorder(
borderRadius:
BorderRadius.vertical(top: Radius.circular(25.0))),
backgroundColor: Colors.yellow,
context: context,
isScrollControlled: true,
builder: (context) => Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: SizedBox(
height: MediaQuery.of(context).size.height - 80,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SingleChildScrollView(
child: Column(
children: [
for (var m in this.messages) ...[
Text(m)
]
],
),
),
TextField(
textAlign: TextAlign.left,
decoration: InputDecoration(
hintText: 'Message',
contentPadding: EdgeInsets.all(10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
isDense: true,
),
keyboardType: TextInputType.multiline,
maxLines: 4,
minLines: 1,
//controller: textController,
textInputAction: TextInputAction.send,
onSubmitted: (value) {
this.setState(() {
this.messages.add(value);
});
},
)
],
),
),
)
);
},
child: const Text('Show Modal Bottom Sheet'),
),
));
}
}
When keyboard is not visible everything is ok (system top panel is visible and AppBar is visible):
However, when keyboard is visible I have a problem as bottom sheet covers both top panel and and AppBar:
Could anyone say how to fix this problem so top panel and AppBar to be visible in both cases (when keyboard is on and when it is off)?
Instead of wrap your whole bottom sheet with padding, try wrap your textField with padding, like this:
builder: (context) => SizedBox(
height: MediaQuery.of(context).size.height - 80,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SingleChildScrollView(
child: Column(
children: [
for (var m in this.messages) ...[Text(m)]
],
),
),
Padding(
padding: EdgeInsets.only(
bottom:
MediaQuery.of(context).viewInsets.bottom),
child: TextField(
textAlign: TextAlign.left,
decoration: InputDecoration(
hintText: 'Message',
contentPadding: EdgeInsets.all(10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
isDense: true,
),
keyboardType: TextInputType.multiline,
maxLines: 4,
minLines: 1,
//controller: textController,
textInputAction: TextInputAction.send,
onSubmitted: (value) {
this.setState(() {
this.messages.add(value);
});
},
),
)
],
),
));
What I am aiming for is, when a user long presses on a particular date, they should be able to enter their weight value, and upon submitting, the modal bottom sheet should close, and the updated weight should be visible as soon as the modal sheet is out of view. But It does not happen.
Instead I have to go to other date and come back to see the changes. Please help me. I am new to flutter.
Here is the demo of the problem :
problem i am facing
Here is the code:
void _modalBottomSheetMenu(DateTime dt) {
showModalBottomSheet(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
context: context,
isScrollControlled: true,
builder: (builder) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text("Add a weight"),
Container(
width: 200.0,
child: TextField(
controller: myController,
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
autofocus: true,
maxLength: 4,
onSubmitted: (value) {
weightValue = double.parse(value);
print("Weight entered is $weightValue");
print("Date passed is $dt");
setState(() {
_events[dt] = [weightValue].toList();
Navigator.pop(context);
});
print(_events[dt][0]);
},
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Weight',
hintText: 'Enter your weight'),
),
),
],
);
},
);
}
BuildEventList : This contains the weight to be printed
import 'package:flutter/material.dart';
class BuildEventList extends StatefulWidget {
String weight;
BuildEventList(this.weight);
#override
_BuildEventListState createState() => _BuildEventListState();
}
class _BuildEventListState extends State<BuildEventList> {
#override
void setState(fn) {
// TODO: implement setState
super.setState(fn);
}
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
border: Border.all(width: 0.8),
borderRadius: BorderRadius.circular(12.0),
),
margin: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
child: Container(
width: double.infinity,
child: Center(child: Text("${widget.weight}")),
),
);
}
}
This is where it is called :
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title), actions: [
IconButton(
icon: Icon(Icons.add),
color: Colors.white,
onPressed: () {},
)
]),
body: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
_buildTableCalendar(),
const SizedBox(height: 8.0),
//_buildButtons(),
const SizedBox(height: 8.0),
Expanded(
child: BuildEventList(_selectedEvents.length > 0
? _selectedEvents[0].toString()
: "No weight given!")),
],
),
);
}
I'm working on an app that will get only 2 inputs from the user, maybe 3 in the future. So I use showDialog with 2 inputfield and 2 buttons. Very simple. Looks pretty much like this:
enter image description here
It shows up perfectly in the main screen if it's being called as a function. But I would like to use that same dialog in another screen in the app and just change the text on one of the buttons. Since the dialog code it's long and I don't want to repeat it, I want to put it in a new StatefulWidget (to retrieve the information from the input fields and clear them afterwards). Now the problem is that I can't find a way to return the dialog from an external widget. I don't know if it's actually impossible because of the whole async Widget incompatibility or I'm just too stupid to figure this out.
This is the code for my dialog (as a function):
_dialog() async {
await showDialog<String>(
context: context,
child: ButtonBarTheme(
data: ButtonBarThemeData(alignment: MainAxisAlignment.center),
child: AlertDialog(
contentPadding: const EdgeInsets.all(20.0),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: EdgeInsets.only(bottom: 15),
child: new TextField(
// onSubmitted: next,
autofocus: true,
controller: _title,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(bottom: 2),
labelText: 'Title',
hintText: 'Example: New Smartphone',
),
),
),
TextField(
autofocus: true,
controller: _codigo,
decoration: InputDecoration(
contentPadding: EdgeInsets.zero,
labelText: 'Code',
hintText: 'Example: EC20008347607',
),
),
],
),
actions: [
Row(
children: [
Container(
padding: EdgeInsets.only(right: 35, bottom: 5),
child: FlatButton(
color: Colors.cyan[600],
child: const Text('CANCEL'),
onPressed: () {
Navigator.pop(context);
}),
),
Container(
padding: EdgeInsets.only(left: 15, bottom: 5),
child: FlatButton(
color: Colors.cyan[600],
child: const Text('ADD'),
onPressed: () {
setState(() {
_title.text = '';
_code.text = '';
});
Navigator.pop(context);
},
),
),
],
),
],
),
),
);
}
Thanks in advance for any help. I'm a beginner.
You can put it in another dart file that accepts any property values that aren't static, like this:
CustomAlertDialog({String leftButtonText, String rightButtonText}) async {
return AlertDialog(
contentPadding: const EdgeInsets.all(20.0),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: EdgeInsets.only(bottom: 15),
child: new TextField(
// onSubmitted: next,
autofocus: true,
controller: _title,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(bottom: 2),
labelText: 'Title',
hintText: 'Example: New Smartphone',
),
),
),
TextField(
autofocus: true,
controller: _codigo,
decoration: InputDecoration(
contentPadding: EdgeInsets.zero,
labelText: 'Code',
hintText: 'Example: EC20008347607',
),
),
],
),
actions: [
Row(
children: [
Container(
padding: EdgeInsets.only(right: 35, bottom: 5),
child: FlatButton(
color: Colors.cyan[600],
child: const Text('$leftButtonText'),
onPressed: () {
Navigator.pop(context);
}),
),
Container(
padding: EdgeInsets.only(left: 15, bottom: 5),
child: FlatButton(
color: Colors.cyan[600],
child: const Text('$rightButtonText'),
onPressed: () {
setState(() {
_title.text = '';
_code.text = '';
});
Navigator.pop(context);
},
),
),
],
),
],
),
),
);
}
I think we have to build our widget from the ground up as there is no dialog box that exposes the state. Hope this helps:
https://api.flutter.dev/flutter/widgets/StatefulBuilder-class.html
Try my code snippet
**
MaterialButton(
color: Colors.blue,
height: 50,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)),
),
textColor: Colors.white,
child: Text('Show Info Dialog',),
onPressed: () {
SimpleDialogs.showinfoDialog(context: context, title: "Something insert here");
},
Below is my flutter code and I would like to make the leading calendar icon launch a calendar widget for date selection in the last textfield just before the raised button as marked below in code.
** widget starts inside stateful class**
#override
Widget build(BuildContext context) {
var db = DBHelper();
return Scaffold(
appBar: AppBar(
title: Text('Add'),
),
body: Container(
padding: EdgeInsets.only(top: 30, left: 50, right: 50),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
TextField(
keyboardType: TextInputType.text,
decoration: InputDecoration(
icon: Icon(Icons.bookmark), hintText: 'nickname'),
controller: nameController,
),
const SizedBox(height: 15),
TextField(
decoration: InputDecoration(
icon: Icon(Icons.date_range), hintText: 'date created'),
controller: otherController,
),
const SizedBox(height: 50),
RaisedButton(
onPressed: () {
db.saveAssets(Asset(
name: nameController.text,
other: otherController.text));
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MyAssetsList()),
);
},
padding: EdgeInsets.only(left: 18, right: 18),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
textColor: Colors.white,
color: Colors.lightGreen,
splashColor: Colors.lightGreenAccent,
child: const Text(
'Save',
style: TextStyle(fontSize: 20),
),
),
],
),
),
),
);
}
}
One more solution.
If you want only the calendar icon to be tapable (while still having similar design to the one you've provided):
Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.date_range),
padding: EdgeInsets.zero,
onPressed: () {
print('Yay!');
},
),
Expanded(
child: TextField(
decoration: InputDecoration(
hintText: 'Date Created',
),
readOnly: true, // Or wrap the input with AbsorbPointer if you do not want the field to get highlighted by taping on it
),
),
],
)
If you want to let the user input the date by typing - just remove the readOnly attribute from the input.