flutter form data disappears when I scroll - flutter

I have a widget, that has an image element and and expanded listview of form elements that as I fill out and scroll the data disappears when it scrolls behind the image. It is not throwing any errors when I debug and it happens on any field that scrolls behind the image at the top of the widget. Any ideas?
#override
Widget build(BuildContext context) {
var _children = <Widget>[
new Center(
child: new Text(widget.prov.fname + widget.prov.lname,
style: new TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
),
),
new Center(
child: new Container(
padding: new EdgeInsets.only(
left: 125.0, right: 125.0, bottom: 50.0),
child: new Image.network('http://$baseurl:8080/getimage/'+widget.prov.pic.assetName),
)
),
new Form(
key: _formKey,
autovalidate: _autovalidate,
onWillPop: _warnUserAboutInvalidData,
child: new Expanded(
child: new ListView(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
children: <Widget>[
new TextFormField(
decoration: const InputDecoration(
icon: const Icon(Icons.person),
hintText: 'First Name?',
labelText: 'First Name *',
),
onSaved: (String value) { referral.fname = value; },
validator: _validateName,
),
new TextFormField(
decoration: const InputDecoration(
icon: const Icon(Icons.person),
hintText: 'Last Name?',
labelText: 'Last Name *',
),
onSaved: (String value) { referral.lname = value; },
validator: _validateName,
),
new TextFormField(
decoration: const InputDecoration(
icon: const Icon(Icons.phone),
hintText: 'How to contact?',
labelText: 'Phone Number *',
prefixText: '+1'
),
keyboardType: TextInputType.phone,
onSaved: (String value) { referral.contact = value; },
validator: _validatePhoneNumber,
// TextInputFormatters are applied in sequence.
inputFormatters: <TextInputFormatter> [
WhitelistingTextInputFormatter.digitsOnly,
// Fit the validating format.
_phoneNumberFormatter,
],
),
new TextFormField(
decoration: const InputDecoration(
hintText: 'Tell us about patient',
helperText: 'It does not have to be detailed yet',
labelText: 'Referral Details',
),
maxLines: 5,
),
new _DateTimePicker(
labelText: 'DOB',
selectedDate: _fromDate,
selectDate: (DateTime date) {
setState(() {
referral.dob = date;
});
},
),
new InputDecorator(
decoration: const InputDecoration(
labelText: 'Type of Appointment',
hintText: 'Choose an Appointment Type',
),
isEmpty: _typeAppt == null,
child: new DropdownButton<String>(
value: _typeAppt,
isDense: true,
onChanged: (String newValue) {
setState(() {
_typeAppt = newValue;
});
},
items: _allTypeAppt.map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
),
),
],
)
)
),
/*new RefreshIndicator(
child: new ListView.builder(
itemBuilder: _itemBuilder,
itemCount: listcount,
),
onRefresh: _onRefresh,
),*/
];
return new Scaffold(
appBar: new AppBar(title: new Text("My Provider")),
body: new Column(
children: _children,
),
);
}

This is because you are using ListView to render your children. ListView only renders the visible children (has recycling nature). Instead, use Column with SingleChildScrollView.
SingleChildScrollView(child:Column(children:yourFormChildren));

I think the problem is that you don't save the values which were put into the TextFields (to a state for example).
From your code I assume you are using the ListView.builder() to set up your ListView. This method, as stated in the documentation, renders only the children, which are in view. Once you scroll a child out of view, it is removed from the ListView and only added again, once you scroll it into view. Because the TextField is removed, the value is removed as well.
To permanently have the value saved, I would advice to use TextFields and save the input to state in the onChanged() method of the TextField, or make use of TextEditingController.

Using TextEditorController it's quite simple:
For "First Name" add==>
TextEditingController nameController = new TextEditingController();
and
`new TextFormField(
decoration: const InputDecoration(
icon: const Icon(Icons.person),
hintText: 'First Name?',
labelText: 'First Name *',
),
validator: _validateName,
controller: nameController,
),`
In your onSubmit() ==>
print(nameController.text)

if you have TextFormField that you auto generate by listView.builder()
you can do this solution
List<TextEditingController> generalController=[];
#override
void initState() {
super.initState();
for(int i=0;i<100;i++){
generalController.add(TextEditingController(text: ""));
}}
first define list that contain list of TextEditingController
and after that initialize it with default value inside initState
and inside every item in listview.builder()
use controller with index
like that
ListView.builder(itemBuilder: (context,int index){
CustomTextFromField(
textEditingController: generalController[index],
hint: AppLocalizations.of(context)!.translate("subject_name"),
texInputType: TextInputType.text,
),
},
itemCount: state.subjectList.length,

I had the same issue, I was using ListView and the values go missing when i was scroll, Just as someone above mentioned(Suman Maharjan) i tried using SingleChildScrollView with Column and issue is resolved now.

Related

Error: The parameter 'onSubmit' can't have a value

Hi I have created a default form field, in a separate dart file called components, and I have login_screen.dart also.
there are many errors I don't know how to fix it, and make the code work, I will put down the code of the component.dart code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
Widget defaultButton(
{double width = double.infinity,
Color background = Colors.blue,
double radius = 10.0,
required Function function,
required String text,
bool isUpperCase = true}) =>
Container(
height: 40.0,
width: width,
child: MaterialButton(
onLongPress: () {},
onPressed: function(),
child: Text(
isUpperCase ? text.toUpperCase() : text.toLowerCase(),
style: TextStyle(color: Colors.white),
)),
decoration: BoxDecoration(
borderRadius: BorderRadiusDirectional.circular(radius),
color: background,
),
);
Widget defaultFormFeild({
required TextEditingController controller,
required TextInputType type,
Function onSubmit,
Function onChange,
required Function validate,
required var label,
required IconData prefix,
}) =>
TextFormField(
controller: controller,
keyboardType: type,
onFieldSubmitted: onSubmit(),
onChanged: onChange(),
validator: validate(),
decoration: InputDecoration(
labelText: label,
prefixIcon: Icon(prefix),
border: OutlineInputBorder()
),
);
and here is the code of the login_screen.dart:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:udemy_flutter/shared/components/components.dart';
class LoginScreen extends StatelessWidget {
var emailController = TextEditingController();
var passController = TextEditingController();
var formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Center(
child: SingleChildScrollView(
child: Form(
key: formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Login',
style: TextStyle(
fontSize: 40.0,
fontWeight: FontWeight.bold
),
),
const SizedBox(
height: 40.0,
),
defaultFormFeild(
controller: emailController,
label: 'Email',
prefix: Icons.email,
type: TextInputType.emailAddress,
validate: (String value){
if(value.isEmpty != null){
return 'Email Cannot Be Empty';
}
return null;
}
),
const SizedBox(
height: 15.0,
),
TextFormField(
controller: passController,
obscureText: true,
keyboardType: TextInputType.visiblePassword,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Password',
prefixIcon: Icon(
Icons.lock
),
suffixIcon: Icon(
Icons.remove_red_eye,
)
),
onChanged: (value) {
print(value);
},
onFieldSubmitted: (value) {
print(value);
},
validator: (value) {
if(value!.isEmpty){
return 'Password cannot be empty';
}
return null;
},
),
const SizedBox(
height: 10.0,
),
defaultButton(
function: (){
print(emailController.text);
print(passController.text);
},
text: 'Login',
),
const SizedBox(
height: 10.0,
),
defaultButton(
text: 'ReGister',
function: () {
print('You have just clicked on register');
},
background: Colors.red,
isUpperCase: false
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Don\'t you have an account?'),
TextButton(onPressed: () {}, child: const Text(
'Register Now'
))
],
)
],
),
),
),
),
),
);
}
}
Idk if all the problems came from a null-safety feature in a flutter because I'm new in this technology.
Why
The reason this happens is because with null safety enabled, your functions onSubmit and onChange can't be null.
Solution
I would do it this way:
Widget defaultFormFeild({
required TextEditingController controller,
required TextInputType type,
Function? onSubmit, //Add question mark
Function? onChange, //Add question mark
required Function validate,
required var label,
required IconData prefix,
}) =>
TextFormField(
controller: controller,
keyboardType: type,
onFieldSubmitted: onSubmit != null? onSubmit() : null, //do null checking
onChanged: onChange != null? onChange() : null, //do null checking
validator: validate(),
decoration: InputDecoration(
labelText: label,
prefixIcon: Icon(prefix),
border: OutlineInputBorder()
),
);

how to get save the value from textfromfield and pass it back to page?

import 'package:flutter/material.dart';
import 'package:mmitra/widgets/header.dart';
import 'home.dart';
class CreateAccount extends StatefulWidget {
#override
_CreateAccountState createState() => _CreateAccountState();
}
class _CreateAccountState extends State<CreateAccount> {
late String username;
final _key = Global Key<FormState>();
#override
Widget build(BuildContext parentContext) {
return Scaffold(
appBar: header(context, titleText: 'Create Account'),
body: ListView(children: [
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.only(top: 25),
child: Center(
child: Text(
'Create a username',
style: TextStyle(fontSize: 25.0),
),
),
),
Padding(
padding: EdgeInsets.all(16.0),
child: Form(
child: TextFormField(
key: _key,
// controller: myController,
onSaved: (val) => username = val!,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelStyle: TextStyle(fontSize: 15),
labelText: 'Username',
hintText: 'Must be at least 3 Characters'),
),
),
),
GestureDetector(
onTap: () {
_key.currentState!.save();
Navigator.pop(context, username
);
},
child: Container(
height: 50,
width: 300,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(7)),
child: Center(
child: Text(
'Submit',
style:
TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
),
),
),
),
],
),
),
]),
);
}
}
and I'm getting below shown errors:
Exception caught by gesture
The following Cast Error was thrown while handling a gesture
Null check operator used on a null value
I just want to get the textfromfield value and i want to pass it to the home.dart page in order to create the document in firebase collection
you must define a EditTextControll() ex:textController and set it to TextFormField to controller paramerter , and then get text as textController.text and pass with Navigatoer .
for pass wihtin first screen to two screen
Firstly /
TextEditingController controller = TextEditingController();
Secoundly /
body: Form(
child: TextFormField(
controller: controller,
onTap: (){
//here SettingsScreen() is example
// name is paramerter in the secound screen
Navigator.push(context,
MaterialPageRoute(builder: (context)=>SettingsScreen(name:controller.text),),
);
},
),
),
You added key in TextFormField
Form(
child: TextFormField(
key: _key,
// controller: myController,
onSaved: (val) => username = val!,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelStyle: TextStyle(fontSize: 15),
labelText: 'Username',
hintText: 'Must be at least 3 Characters'),
),
),
),
Remove it from TextFormField and Add it in Form
Just Like:
Form(
key: _key,
child: TextFormField(
// controller: myController,
onSaved: (val) => username = val!,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelStyle: TextStyle(fontSize: 15),
labelText: 'Username',
hintText: 'Must be at least 3 Characters'),
),
),
),
This will Solve your Issue.

Remove scrollbar at right from multiline TextField - Flutter

I have TextField purchaseCommentField() within the structure as below:
#override
Widget build(BuildContext context)
{
return GestureDetector(
onTap: CommonUtils.endEditing(context),
child: Container(
width: _width,
color: Colors.white,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
....
...
Visibility(
visible: _additionalInfo != null,
child: purchaseCommentField()
),
rowSpacer(16.0),
actionButton(context)
],
)
)
),
);
}
Widget purchaseCommentField()
{
return TextField(
controller: _purchaseCommentController,
minLines: 1,
maxLines: null,
keyboardType: TextInputType.multiline,
style: new TextStyle(fontSize: 14.0),
decoration: new InputDecoration(
labelText: 'Additional Info',
border: OutlineInputBorder(),
),
);
}
When I focus textfield, I got unwanted scrollbar at right inside the field:
This issue occured when I set fontSize:14.0. When I remove that or set fontSize to 16.0 then there is no scrollbar at right:
Is there a way to remove that scrollbar in textfield ?
try using TextFormField,
TextFormField(
controller: textController,
validator: (value) {
if (value.trim().isEmpty) {
return _reportTypeModel.language.msgEnterDesc;
}
return null;
},
style: new TextStyle(fontSize: 14.0),
maxLength: 500,
decoration: InputDecoration(
labelText: _reportTypeModel.language.description,
),
minLines: 4,
maxLines: 6,
keyboardType: TextInputType.multiline,
textInputAction: TextInputAction.next,
),
Output:
There's an open issue on github regarding this.
For now you can fix this by creating a custom ScrollBehavior and overriding buildScrollbar method:
class CustomScrollBehavior extends ScrollBehavior {
const CustomScrollBehavior();
#override
Widget buildScrollbar(context, child, details) {
return child;
}
}
And then wrap your TextField with ScrollConfiguration widget:
return ScrollConfiguration(
behavior: const CustomScrollConfiguration(),
child: TextField(
// Your text-field params
),
);
This works for TextFormField too.

hint not working for DropdownButtonFormField in Flutter

I have a form in Flutter with textformfield and dropdownbuttonformfield. While running my app hint is not working for me. hint not shown in dropdownbuttonformfield. It's showing kkk as initial value not showing Select City.
I'm using StatefulWidget here.
help me to solve this Problem.
Thanks in Advance.
class _AddTripState extends State<AddTrip> {
var formKey = GlobalKey<FormState>();
TextEditingController nameController = TextEditingController();
TextEditingController numberController = TextEditingController();
TextEditingController datecontroller = TextEditingController();
final format = DateFormat("yyyy-MM-dd");
DateTime _dateTime;
List<String> name = ['kkk', 'rrr'];
String _dropdownvalue = 'kkk';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Add Trip"),
),
body: Form(
key: formKey,
child: ListView(
children: <Widget>[
Text(
'Name',
textAlign: TextAlign.left,
),
TextFormField(
decoration: _inputDecoration(),
keyboardType: TextInputType.text,
controller: nameController,
validator: textValidator,
),
Text(
'Number',
textAlign: TextAlign.left,
),
TextFormField(
decoration: _inputDecoration(),
controller: numberController,
keyboardType: TextInputType.number,
validator: numberValidator,
),
Text(
'Date',
textAlign: TextAlign.left,
),
TextFormField(
readOnly: true,
controller: datecontroller,
validator: dateValidator,
decoration: InputDecoration(
border: OutlineInputBorder(),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.amber)),
errorStyle: TextStyle(color: Colors.amber),
suffixIcon: GestureDetector(
child: Icon(
Icons.date_range,
),
onTap: () {
showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2018),
lastDate: DateTime(2020))
.then((value) {
setState(() {
datecontroller.text =
DateFormat("yyyy-MM-dd").format(value);
});
});
},
),
),
),
DropdownButtonFormField<String>(
hint: Text('Select City'),
validator: _cityValidator,
decoration: InputDecoration(border: OutlineInputBorder()),
items: name.map((value) {
return DropdownMenuItem<String>(
child: Text(value), value: value);
}).toList(),
value: _dropdownvalue,
onChanged: (newValue) {
setState(() {
_dropdownvalue = newValue;
});
},
),
RaisedButton(
onPressed: submit,
child: Text('Add Trip'),
)
],
)),
);
}
Where i'm wrong?
The hint is Displayed if the value is null.
so in your code - make - String _dropdownvalue = 'kkk'; change to - String _dropdownvalue; only
You need to use InputDecoration for that purpose:
decoration: InputDecoration(labelText:'Select City'),

Flutter Layout Problem. How to get all the fields the same length

I'm developing a registration screen.
I can't get all the fields with the same length in the screen.
They are different types of fields: ListTile, Dropdown button, and Checkbox. I'm new to Flutter. Can I apply any parameter to get the same padding on both sides?
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Register"),
),
body: new Stack(
children: [
new Padding(
padding: const EdgeInsets.only(
left: 16.0, top: 30.0, right: 16.0, bottom: 16.0),
child: ListView(
children: <Widget>[
new ListTile(
leading: const Icon(Icons.person),
title: TextField(
decoration: InputDecoration(
labelText: "Username : ", hintText: " Username ",
errorText: _correctUsername ? null : 'Complete Username',),
onSubmitted: (value) {
_checkInput();
},
controller: _usernameController,
),
),
new FormField(
builder: (FormFieldState state) {
return InputDecorator(
decoration: InputDecoration(
icon: const Icon(Icons.person),
labelText: 'Gender',
errorText: _correctGender ? null : 'Select Gender',),
child: new DropdownButtonHideUnderline(
child: new DropdownButton(
value: _selectedGender,
items: _dropDownMenuGender,
onChanged: changedDropDownGender,
),
),
);
},
),
new ListTile(
leading: const Icon(Icons.person),
title: TextField(
decoration: InputDecoration(
labelText: "About me : ", hintText: " About me "),
controller: _aboutController,
),
),
new FormField(
builder: (FormFieldState state) {
return InputDecorator(
decoration: InputDecoration(
icon: const Icon(Icons.person),
labelText: 'I have a car',
),
child: new Checkbox(
value: _havecar, onChanged: _havecarChanged));
},
),
],
),
),
]
),
);
}
Any help will be appreciated.
Regards.
Replace your ListTiles with just and note the icon property.
TextField(
decoration: InputDecoration(
labelText: "Username : ",
hintText: " Username ",
icon: const Icon(Icons.person),
errorText: _correctUsername ? null : 'Complete Username',
),
onSubmitted: (value) {
_checkInput();
},
controller: _usernameController,
),