State of my Widget not changing in flutter when updating value - flutter

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!")),
],
),
);
}

Related

How to set top padding for bottom sheet with text field in Flutter?

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);
});
},
),
)
],
),
));

Why is my TextField and List not showing when both are together in flutter

I have just started learning flutter this week!, After following a 5 hour video I decided that I would be a good Idea to work on a to do list using my knowledge. I have been having some problems with the layout order because I am used to react native and html. So I have a TextField in which a user can type the a task and then submit it so that it can appear on a list of the added tasks which is below this textfield. In the process I realized that the code is not displaying anything. The code just shows something if the TextField is removed or the list is removed but it looks that they cant be in the same page. How can I fix that problem?
My current code which doesnt display anything (main.dart)
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
List<String> _toDoItems = [];
void _addToDoItem(String task) {
if(task.length > 0) {
setState(() {
_toDoItems.add(task);
});
}
}
Widget _buildToDoItem(String toDoText) {
return ListTile(
title: Text(toDoText)
);
}
Widget _buildToDoList() {
return ListView.builder(
itemBuilder: (context, index) {
if (index < _toDoItems.length) {
return _buildToDoItem(_toDoItems[index]);
}
},
);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(50),
child: AppBar(
centerTitle: true,
backgroundColor: Colors.red,
title: Text('To Do List', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold,),),
)
),
backgroundColor: Colors.white,
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.all(22),
child: TextField(
autofocus: true,
onSubmitted: (val) {
_addToDoItem(val);
},
),
), _buildToDoList(),
],
),
),
);
}
}
Now the following code is the one that does display the list but not the TextField
body: _buildToDoList(),
code that does display the TextField but not the List
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.all(22),
child: TextField(
autofocus: true,
onSubmitted: (val) {
_addToDoItem(val);
},
decoration: InputDecoration(
hintText: 'Add a tak here...',
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0)),
borderSide: BorderSide(color: Colors.red, width: 2),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0)),
borderSide: BorderSide(color: Colors.red, width: 1.5),
),
),
),
), // the list widget here is removed so that the text field could appear
],
),
for button next to text field:
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.all(22),
child: Row(children: [
TextField(
autofocus: true,
onSubmitted: (val) {
_addToDoItem(val);
},
decoration: InputDecoration(
hintText: 'Add a tak here...',
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0)),
borderSide: BorderSide(color: Colors.red, width: 2),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0)),
borderSide: BorderSide(color: Colors.red, width: 1.5),
),
),
),
RaisedButton(
child: Text('ADD'),
onPressed: null,
),
],)
),
_buildToDoList(),
],
),
You can copy paste run full code below
You can wrap ListView with Expanded
code snippet
Widget _buildToDoList() {
return Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
if (index < _toDoItems.length) {
return _buildToDoItem(_toDoItems[index]);
}
},
),
);
}
working demo
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
List<String> _toDoItems = [];
void _addToDoItem(String task) {
if (task.length > 0) {
setState(() {
_toDoItems.add(task);
});
}
}
Widget _buildToDoItem(String toDoText) {
return ListTile(title: Text(toDoText));
}
Widget _buildToDoList() {
return Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
if (index < _toDoItems.length) {
return _buildToDoItem(_toDoItems[index]);
}
},
),
);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(50),
child: AppBar(
centerTitle: true,
backgroundColor: Colors.red,
title: Text(
'To Do List',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
)),
backgroundColor: Colors.white,
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.all(22),
child: TextField(
autofocus: true,
onSubmitted: (val) {
_addToDoItem(val);
},
),
),
_buildToDoList(),
],
),
),
);
}
}
full code 2
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
List<String> _toDoItems = [];
void _addToDoItem(String task) {
if (task.length > 0) {
setState(() {
_toDoItems.add(task);
});
}
}
Widget _buildToDoItem(String toDoText) {
return ListTile(title: Text(toDoText));
}
Widget _buildToDoList() {
return Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
if (index < _toDoItems.length) {
return _buildToDoItem(_toDoItems[index]);
}
},
),
);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(50),
child: AppBar(
centerTitle: true,
backgroundColor: Colors.red,
title: Text(
'To Do List',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
)),
backgroundColor: Colors.white,
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.all(22),
child: Row(
children: [
Expanded(
flex: 1,
child: TextField(
autofocus: true,
onSubmitted: (val) {
_addToDoItem(val);
},
decoration: InputDecoration(
hintText: 'Add a tak here...',
enabledBorder: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(12.0)),
borderSide: BorderSide(color: Colors.red, width: 2),
),
focusedBorder: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(12.0)),
borderSide:
BorderSide(color: Colors.red, width: 1.5),
),
),
),
),
Expanded(
flex: 1,
child: RaisedButton(
child: Text('ADD'),
onPressed: null,
),
),
],
)),
_buildToDoList(),
],
),
),
);
}
}

Flutter stack layout container use remaining height

I'm starting with Flutter.
I'm building a layout to look like
I'm using Stack to build this layout, where the part in background color is another Stack child with parent Container height to a fixed value.
The code I have written till now is
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:whatsappwithoutcontact/components/form_fields.dart';
import 'package:whatsappwithoutcontact/screens/info/info-screen.dart';
class MessageScreen extends StatefulWidget {
#override
_MessageScreenState createState() => _MessageScreenState();
}
class _MessageScreenState extends State<MessageScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('WhatsApp without Contact'),
backgroundColor: Colors.transparent,
elevation: 0.0,
actions: [
IconButton(
icon: Icon(Icons.info),
onPressed: _onInfoPressed,
)
],
),
extendBodyBehindAppBar: true,
body: MessageContainer()
);
}
void _onInfoPressed() {
Navigator.of(context).push(
MaterialPageRoute<void> (
builder: (BuildContext context) {
return InfoScreen();
}
)
);
}
}
class MessageContainer extends StatefulWidget {
#override
_MessageContainerState createState() => _MessageContainerState();
}
class _MessageContainerState extends State<MessageContainer> {
static const double avatarRadius = 35;
static const double titleBottomMargin = (avatarRadius * 2) + 18;
static const double _headerHeight = 350.0;
final _formKey = GlobalKey<FormState>();
final _messageFieldFocusNode = FocusNode();
#override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Stack(
children: [
Container(
height: _headerHeight,
child: Stack(
children: <Widget>[
Container(
child: ClipPath(
clipper: HeaderClipper(avatarRadius: avatarRadius),
child: CustomPaint(
size: Size(MediaQuery.of(context).size.width, _headerHeight),
painter: HeaderPainter(
color: Colors.green,
avatarRadius: avatarRadius
),
),
),
),
Positioned(
left: 0,
right: 0,
child: Container(
padding: EdgeInsets.only(top: 80.0),
margin: EdgeInsets.all(50.0),
child: Column(
children: <Widget>[
FormTextField(
labelText: 'Country Code',
validator: (value) {
if (value.isEmpty) {
return 'Required';
}
return null;
}
),
SizedBox(height: 15.0,),
FormTextField(
labelText: 'Phone Number',
validator: (value) {
if (value.isEmpty) {
return 'Required';
}
return null;
},
)
],
),
),
),
Align(
alignment: Alignment.bottomCenter,
child: CircleAvatar(
radius: avatarRadius,
backgroundColor: Colors.green,
child: IconButton(icon: Icon(Icons.message), onPressed: _onAddMessageButtonClick,),
),
)
],
),
),
SingleChildScrollView(
child: Padding(
padding: EdgeInsets.symmetric(
vertical: _headerHeight,
horizontal: 50
),
child: Column(
children: [
TextFormField(
keyboardType: TextInputType.multiline,
maxLines: 4,
focusNode: _messageFieldFocusNode,
decoration: InputDecoration(
labelText: 'Message',
fillColor: Colors.white,
labelStyle: TextStyle(
color: _messageFieldFocusNode.hasFocus ? Colors.green : Colors.grey
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.grey
)
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.green
)
)
),
)
],
),
),
),
],
)
);
}
}
The first Container inside the first Stack is the green background part and SingleChildScrollView is the part below the green color background.
The SingleChildScrollView is making the lower part scrollable whereas I want it to be fixed and take up remaining space below the message icon in the center.
I tried using Container but then the Message input field is not displayed.
How can I use the remaining space below the Stack layout?
Is my layout structure good according to the design. I need suggestions on how to improve it, if not good.
Replace the first Stack widget with Column, now you can wrap your SingleChildScrollView widget into an Expanded widget, the Expanded widget works only inside Column and Row to fill the available space.
Don't forget to remove vertical padding from the Message input field.

Keyboard hiding my bottom sheet text field in flutter

Keyboard hiding my bottom sheet text field in flutter.
I opened a bottom sheet for textfield but when starting to enter some text, keyboard opens and hides textfield bottom sheet and 'save' buttom too, so not able to see what i'm typing in textfield.
see below image
I want this result:
Code:
Opening bottom sheet on click of '+ Add' button.
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Form(
key: formKey,
child: Container(
padding: const EdgeInsets.all(8),
height: MediaQuery.of(context).size.height/4.5,
// color: Colors.red,
child: Column(
children: <Widget>[
Container(
padding: const EdgeInsets.all(10),
child: TextFormField(
controller: _noteTextController,
maxLines: 2,
minLines: 2,
decoration: InputDecoration(
hintText: "Add Note",
border: InputBorder.none
),
validator: (value){
if(value.trim().isEmpty){
return 'Notes can\'t be empty';
} else {
return null;
}
},
),
),
Container(
padding: const EdgeInsets.all(8),
width: MediaQuery.of(context).size.width,
// color: Colors.black,
alignment: Alignment.topRight,
child: InkWell(
onTap: (){
if (formKey.currentState.validate()) {
formKey.currentState.save();
DateTime noteDate = DateTime.now();
setState(() {
notes.add(
NoteModel(
date: noteDate,
noteText: _noteTextController.text
)
);
});
Navigator.of(context).pop();
_noteTextController.clear();
}
},
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(8)
),
width: MediaQuery.of(context).size.width/5,
height: MediaQuery.of(context).size.height/25 ,
child: Text("Save", style:TextStyle(
color: Colors.white,
fontSize: 19
)),
),
),
)
],
),
),
);
},
);
Here is a simple workaround that would suite your use case:
Using the minimal code from your example, try to wrap the Widget with AnimatedPadding and wraps it inside SingleChildScrollView to push the BottomSheet from bottom and thus preventing keyboard from overlapping.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: 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: const MyStatelessWidget(),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Center(
child: TextButton.icon(
icon: Icon(
Icons.add,
color: Colors.blue,
),
label: Text(
'Add',
style: TextStyle(
color: Colors.blue,
),
),
onPressed: () {
showModalBottomSheet<void>(
// isScrollControlled: true,
context: context,
builder: (BuildContext context) {
return Form(
key: key,
child: SingleChildScrollView(
child: AnimatedPadding(
padding: MediaQuery.of(context).viewInsets,
duration: const Duration(milliseconds: 100),
curve: Curves.decelerate,
child: Column(
children: <Widget>[
Container(
padding: const EdgeInsets.all(10),
child: TextFormField(
maxLines: 2,
minLines: 2,
decoration: InputDecoration(
hintText: "Add Note", border: InputBorder.none),
),
),
],
),
),
),
);
},
);
},
),
);
}
}

How can I make a number counter app using textfield in flutter?

import 'package:flutter/material.dart';
void main() => runApp(Spent());
class Spent extends StatefulWidget {
#override
SpentState createState() => SpentState();
}
class SpentState extends State<Spent> {
final _controller = TextEditingController();
String name = '';
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Container (
padding: const EdgeInsets.all(30.0),
child: Container(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(name),
TextFormField(
textInputAction: TextInputAction.done,
controller: _controller,
decoration: InputDecoration(
fillColor: Colors.black,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(),
),
),
keyboardType: TextInputType.number
),
FlatButton(
child: Text("Enter"),
onPressed: () {
setState(() {
name = _controller.text;
});
},
)
]
)
),
)
)
)
);
}
}
Like so, I have a TextFormField. What I want my application to do is subtract the number that is currently existing using textfield. So for example if I have the number 5000, the user would type 2000 and press enter. This would make the number to 3000. How can I make this?
Here's a possible solution with basic error checking.
class SpentState extends State<Spent> {
final _controller = TextEditingController();
double value = 5000;
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Container(
padding: const EdgeInsets.all(30.0),
child: Container(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(value.toString()),
TextFormField(
textInputAction: TextInputAction.done,
controller: _controller,
decoration: InputDecoration(
fillColor: Colors.black,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(),
),
),
keyboardType: TextInputType.number),
FlatButton(
child: Text("Enter"),
onPressed: () {
//check if we can parse it
if (double.tryParse(_controller.text) == null)
return; //can't parse it
double enteredValue =
double.parse(_controller.text);
setState(() {
value -= enteredValue;
});
},
)
])),
))));
}
}