Keyboard disappearing when moving the focus to the next TextFormField flutter - flutter

This the form where I'm trying to move the focus. All is working fine till the field title, where I want to move it to a textField phone number but in doing so instead of moving the focus the soft keyboard disappears. I tried to attached scrollController to the SingleScrollView and then move it in onSaved in the textfield before this one I want to get focus:
controller.singleSclollViewController.jumpTo(controller.singleSclollViewController.position.maxScrollExtent);
But it is doing nothing.
This is the complete form with that problem
Form(
key: controller.formKey,
child: SingleChildScrollView(
controller: controller.singleSclollViewController,
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
verticalSpaceMedium,
Image.asset(
'assets/graphics/data.png',
),
Container(
padding: EdgeInsets.symmetric(horizontal: 40),
child: GetBuilder<HomeController>(
builder: (builderController) =>
builderController.isPosition
? CustomTextField(
autofocus: true,
focusNode:
controller.adressFocusNode,
validate: (text) => controller
.validateTextField(text),
maxline: 4,
minLine: 2,
height: 80.h,
width: 0.8.sw,
controller:
controller.adressController,
color:
AppColors.primaryColorShade,
//adress
lableText: 'адреса',
)
: CircularProgressIndicator()),
),
verticalSpaceSmall,
Container(
padding: EdgeInsets.symmetric(
horizontal: 40,
vertical: 10,
),
child: TypeAheadFormField<City>(
validator: (text) {
if (globalController
.doesSuggestionExist) {
//there is no such available city
return 'такого доступного міста немає';
}
return controller
.validateTextField(text ?? '');
},
textFieldConfiguration:
TextFieldConfiguration(
controller: controller.cityController,
decoration:
outlineInputTextFormFieldStyle!
.copyWith(
label: Text(
//city
'місто',
style: textfieldLableStyle,
)),
),
onSuggestionSelected: (City city) {
controller.cityController.text =
city.name;
controller.nameFocusNode.requestFocus();
},
itemBuilder: (_, City city) {
return ListTile(
leading: Icon(Icons.location_city),
title: Text(
city.name,
style: headingBlackStyle,
),
);
},
suggestionsCallback: (pattern) async {
return await globalController
.getSuggestions(pattern, '');
}),
),
verticalSpaceSmall,
OneLineTextField(
focusNode: controller.nameFocusNode,
onSubmit: () {
controller.nameFocusNode.unfocus();
controller.titleFocusNode.requestFocus();
},
keybordhType: TextInputType.name,
validator: (text) {
return controller
.validateTextField(text ?? '');
},
//name/"Ім'я та прізвище"
lable: "Ім'я та прізвище",
maxLenght: 25,
controller: controller.nameController),
verticalSpaceSmall,
OneLineTextField(
onSubmit: () {
controller.singleSclollViewController
.jumpTo(controller
.singleSclollViewController
.position
.maxScrollExtent);
controller.phoneFocusNode.requestFocus();
},
focusNode: controller.titleFocusNode,
maxLenght: 25,
keybordhType: TextInputType.name,
validator: (text) {
return controller
.validateTextField(text ?? '');
},
//title/"потрібен титул"
lable: 'Назва оголошення',
controller: controller.titleController),
verticalSpaceSmall,
OneLineTextField(
focusNode: controller.phoneFocusNode,
onSubmit: () => controller
.descripotionFocusNode
.requestFocus(),
maxLenght: 15,
keybordhType: TextInputType.number,
validator: (text) {
return controller
.validateTextField(text ?? '');
},
//phone number/ "телефонний номер"
lable: 'телефонний номер',
controller:
controller.contactNumberController),
verticalSpaceSmall,
Container(
padding: EdgeInsets.symmetric(horizontal: 40),
child: CustomTextField(
onSubmit: () => controller
.descripotionFocusNode
.unfocus(),
focusNode: controller.descripotionFocusNode,
maxLenght: 400,
validate: (text) =>
controller.validateTextField(text),
maxline: 10,
minLine: 5,
height: 120.h,
width: 0.8.sw,
controller: controller.descriptionController,
color: AppColors.primaryColorShade,
//description
lableText: 'опис',
),
),
],
),
),
),

Related

Issue with Login form Layout in Flutter

I'm making a login form in Flutter, I'm using a ListView that has a Container as a child and it's child is a Stack widget which has Positioned children. Because of the Stack, I have to have a bound height, so hence the Container widget, which I gave the height: height: MediaQuery.of(context).size.height * 1.2. If I remove the * 1.2 my Button and and Text widget don't show up, and when I click on the login with * 1.2, my validator pops up, red warning signs shows that your info is entered incorrectly, so I can't see the button anymore. Example in pictures:
This is with height: MediaQuery.of(context).size.height * 1.2
Then I try to login, validator pops, and now I can't see the button nor the text and link below the button:
The problem I am facing is, how do I layout this login form that can only be scrollable as far as it needs, so I don't have empty space after the Button, just to spread the form so it is visible, not get something like this if I increment the height of the Container?
Code:
ListView(
shrinkWrap: true,
children: [
Container(
height: MediaQuery.of(context).size.height * 1.6,
child: Stack(
children: [
Positioned(
width: MediaQuery.of(context).size.width,
top: MediaQuery.of(context).size.width * 0.1,
child: Image.asset(
'assests/images/loginform.png',
scale: 2.5,
height: 60,
width: 119,
),
),
Positioned(
width: MediaQuery.of(context).size.width,
top: MediaQuery.of(context).size.width * 0.35,
child: Padding(
padding: const EdgeInsets.only(left: 24.0, right: 25.0),
child: Column(
children: <Widget>[
Form(
key: _registrationFormKey,
child: Column(
children: [
TextFormField(
textAlign: TextAlign.start,
onChanged: (value) {
context.read<User>().name = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Full name'),
validator: (thisValue) {
if (thisValue.isEmpty) {
return 'Please enter your full name';
}
return null;
},
),
SizedBox(
height: 24.0,
),
TextFormField(
keyboardType: TextInputType.phone,
textAlign: TextAlign.start,
onChanged: (value) {
context.read<User>().phoneNumber = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Phone number'),
validator: _validateMobile,
),
SizedBox(
height: 24.0,
),
TextFormField(
keyboardType: TextInputType.streetAddress,
textAlign: TextAlign.start,
onChanged: (value) {
context.read<User>().address = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Address'),
validator: (thisValue) {
if (thisValue.isEmpty) {
return 'Please enter your address';
}
return null;
},
),
SizedBox(
height: 24.0,
),
TextFormField(
keyboardType: TextInputType.text,
textAlign: TextAlign.start,
onChanged: (value) {
context.read<User>().companyName = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Company name'),
validator: (thisValue) {
if (thisValue.isEmpty) {
return 'Please enter your company name';
}
return null;
},
),
SizedBox(
height: 24.0,
),
TextFormField(
keyboardType: TextInputType.text,
textAlign: TextAlign.start,
onChanged: (value) {
context.read<User>().website = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Website name'),
validator: _validateWebsite),
SizedBox(
height: 24.0,
),
TextFormField(
keyboardType: TextInputType.emailAddress,
textAlign: TextAlign.start,
onChanged: (value) {
context.read<User>().email = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'E-mail address'),
validator: _validateEmail,
),
SizedBox(
height: 24.0,
),
TextFormField(
keyboardType: TextInputType.text,
obscureText: _obscureText,
textAlign: TextAlign.start,
onChanged: (value) {
context.read<User>().password = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Password',
suffixIcon: IconButton(
icon: const Icon(Icons.visibility_outlined),
onPressed: _togglePassVisibility,
),
),
validator: _validatePassword,
),
],
),
),
FormField<bool>(
// 1
initialValue: _agree,
builder: (FormFieldState<bool> state) {
// 2
return Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Checkbox(
// 3
value: state.value,
onChanged: (bool val) => setState(() {
// 4
_agree = val;
// 5
state.didChange(val);
}),
),
const Text('I agree with'),
TextButton(
onPressed: () {},
child: Text('Terms and conditions'),
),
],
),
// 6
state.errorText == null
? Text("")
: Text(state.errorText,
style: TextStyle(color: Colors.red)),
],
);
},
// 7
validator: (val) => _validateTerms(_agree),
),
AlarmButtons(
buttonColour: Color(0xFF29ABE2),
buttonText: 'CREATE ACCOUNT',
buttonTextColour: Colors.white,
buttonBorderSide: Colors.white,
onButtonPress: () async {
if (_registrationFormKey.currentState.validate()) {
signUpToCognito(context);
Navigator.pushNamed(
context, ConfirmRegistrationScreen.id);
}
},
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Already have an account?'),
TextButton(
onPressed: () {
Navigator.pushNamed(context, LoginScreen.id);
},
child: Text('Log in'),
),
],
),
],
),
),
),
],
),
)
],
)
Thanks in advance for the help and suggestions!
there are a couple mistakes (or at least optimizations) in your code. I will go over them one by one:
If you have a small number of children that need to be scrolled, it is better to use a SingleChildScrollView with a Column instead of a list view. ListView builds its children lazily - that is, it only builds widgets that are visible on the screen. If you have only a handful of widgets with no complex animations, then you don't really need that. SingleChildScrollView is more flexible that a ListView.
SingleChildScrollView(
child: Column(
children: [...]
)
)
It seems that you want the image to be on the background with the form validation on top of it. For that, you used a Stack and a Column as children to a ListView. Instead, have the Stack as a parent, with both the ListView and the image as children to the Stack. Now this might produce an error, as the ListView might expand infinitely. A simple solution is to wrap it within a Positioned widget with all its sides set to zero.
Stack(
children: [
BackgroundImageWidget(),
Positioned(
top: 0, bottom: 0, left: 0, right: 0, // or width: screenWidth, height: screenHeight,
child: ListView(...),
)
]
)

Show a loading spinner when sending OTP using Firebase

I want to show a loading spinner whenever user clicks on "SEND OTP" button. I have created a variable _IsLoading which I am setting to true just prior to calling the verifyphone function and then setting it to false afterwards. It seems like it does not have any effect whatsoever on the UI. How can I make this work?
If I replace the verifyPhone with the following line of code, then I do see the spinner :
await new Future.delayed(new Duration(milliseconds: 1500));
I have disabled recaptcha, so my app does not navigate to the recaptcha verification page. But still the spinner does not work.
#override
Widget build(BuildContext context) {
return _isLoading
? Center(child: Loading()):Scaffold(
appBar: AppBar(
title: Text("OTP Verification"),
),
body:SizedBox(
width: double.infinity,
child: Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(20)),
child: SingleChildScrollView(
child: Column(
children: [
SizedBox(height: SizeConfig.screenHeight * 0.05),
Text(
"OTP Verification",
style: headingStyle,
),
Text("Press Send OTP to get a 6 digit code via SMS and enter below.."),
// buildTimer(),
//OtpForm(),
Form(
child: Column(
children: [
SizedBox(height: SizeConfig.screenHeight * 0.15),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: getProportionateScreenWidth(40),
child: TextFormField(
autofocus: true,
maxLength: 1,
obscureText: true,
style: TextStyle(fontSize: 24),
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
decoration: otpInputDecoration,
onChanged: (value) {
nextField(value, pin2FocusNode);
},
),
),
SizedBox(
width: getProportionateScreenWidth(40),
child: TextFormField(
focusNode: pin2FocusNode,
maxLength: 1,
obscureText: true,
style: TextStyle(fontSize: 24),
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
decoration: otpInputDecoration,
onChanged: (value) => nextField(value, pin3FocusNode),
),
),
SizedBox(
width: getProportionateScreenWidth(40),
child: TextFormField(
focusNode: pin3FocusNode,
maxLength: 1,
obscureText: true,
style: TextStyle(fontSize: 24),
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
decoration: otpInputDecoration,
onChanged: (value) => nextField(value, pin4FocusNode),
),
),
SizedBox(
width: getProportionateScreenWidth(40),
child: TextFormField(
maxLength: 1,
focusNode: pin4FocusNode,
obscureText: true,
style: TextStyle(fontSize: 24),
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
decoration: otpInputDecoration,
onChanged: (value) => nextField(value, pin5FocusNode),
),
),
SizedBox(
width: getProportionateScreenWidth(40),
child: TextFormField(
autofocus: true,
focusNode: pin5FocusNode,
obscureText: true,
maxLength: 1,
style: TextStyle(fontSize: 24),
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
decoration: otpInputDecoration,
onChanged: (value) {
nextField(value, pin6FocusNode);
},
),
),
SizedBox(
width: getProportionateScreenWidth(40),
child: TextFormField(
autofocus: true,
focusNode: pin6FocusNode,
maxLength: 1,
obscureText: true,
style: TextStyle(fontSize: 24),
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
decoration: otpInputDecoration,
onChanged: (value) {
if (value.length == 1) {
pin6FocusNode.unfocus();
// Then you need to check is the code is correct or not
}
}
),
),
],
),
SizedBox(height: SizeConfig.screenHeight * 0.15),
DefaultButton(
text: _isLoading?"Sending OTP...":"Send OTP",
press: () async {
setState(() {
_isLoading = true;
});
verifyPhoneNumber();
setState(() {
_isLoading = false;
});
},
),
SizedBox(),
DefaultButton(
text: "Continue",
press: () async {
},
)
],
),
),
SizedBox(height: SizeConfig.screenHeight * 0.1),
GestureDetector(
onTap: () {
// OTP code resend
},
child: Text(
"Resend OTP Code",
style: TextStyle(decoration: TextDecoration.underline),
),
)
],
),
),
),
));
}
I found a solution. You can register a callback in the verifyPhoneNumber function by using then
Right before calling verifyPhoneNumber function, add this:
setState(() {
_isLoading = true;
});
Then in the function's call back, add change _isLoading to false.
await _auth.verifyPhoneNumber(
phoneNumber: '+11345670033',
timeout: const Duration(seconds: 5),
verificationCompleted: verificationCompleted,
verificationFailed: verificationFailed,
codeSent: codeSent,
codeAutoRetrievalTimeout:
codeAutoRetrievalTimeout).then((value) {
setState(() {
_isLoading = false;
});
});

Flutter - How to get value in TextFormField using Navigator

Container(
padding: EdgeInsets.all(15),
child: Column(
children: [
TextFormField(
onTap: () =>
Navigator.of(context).pushNamed(AirportSearchScreen.id).then(
(value)
{
setState(() {
_initValues['departureCity'] = value;
print(_initValues['departureCity']);
});
},
),
decoration: InputDecoration(
labelText: 'Departure City',
),
initialValue: _initValues['departureCity'],
),
],
),
);
When I am printing the value, it is give right result. But I am not able to get the result on TextFormField.
Try the code below :
child: Column(
children: [
TextFormField(
onTap: () =>
Navigator.of(context).pushNamed(AirportSearchScreen.id).then(
(value)
{
setState(() {
_initValues['departureCity'] = value;
print(_initValues['departureCity']);
});
},
),
decoration: InputDecoration(
labelText: 'Departure City',
),
controller: TextEditingController(text: _initValues['departureCity']),
),
],
),

problem with SimpleAutocomplete : Bad state: Too many elements flutter

It's a problem that has been going on for too long. I tried with SimpleAutoComplete or TypeAheadField but I have the same problem.
Simple Auto Complete
Type ahead
With two elements, my sort is succesfull but when i click on the element, I have this three possibilities :
Bad state: Too many elements
return null in my item
never call the action
Autocomplete :
final _nameContributorTextFormFieldDetailsCreateMission = Padding(
padding: EdgeInsets.only(top: 12.0, left: 12.0, bottom: 12.0),
child: SizedBox(
height: 100,
width: 300,
child: SimpleAutocompleteFormField<Employee>(
key: key,
controller: _searchText2Controller,
focusNode: _focusNode,
itemBuilder: (context, contributor) => Padding(
padding: EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Text(
contributor.lastname,
style: TextStyle(fontWeight: FontWeight.bold),
),
Padding(
padding: EdgeInsets.only(left: 4.0),
child: Text(contributor.firstname),
),
],
),
),
onSearch: (search) async => model.employees
.where((contributor) =>
contributor.firstname
.toLowerCase()
.contains(search.toLowerCase()) ||
contributor.lastname
.toLowerCase()
.contains(search.toLowerCase()))
.toList(),
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Nom',
),
itemFromString: (string) => model.employees.singleWhere(
(contributor) =>
contributor.firstname.toLowerCase() == string.toLowerCase(),
orElse: () => null),
onFieldSubmitted: (item) {
print(item);
_searchTextController.text = "${item.firstname}";
},
onSaved: (item) {
print(item);
},
/*onChanged: (Store value) {
model.store = value;
model.setClientOnChangedValue(model.store);
},
onSaved: (Store value) {
model.store = value;
model.setClientOnSavedValue(model.store);
}, */
// validator: (contributor) => contributor == null ? 'Invalid' : null,
),
),
);
TypeAhead :
Padding(
padding: EdgeInsets.only(top: 12.0, left: 12.0, bottom: 12.0),
child: SizedBox(
width: 300,
child: TypeAheadField(
textFieldConfiguration: TextFieldConfiguration(
autofocus: true,
controller: model.typeAheadController,
decoration: InputDecoration(
border: OutlineInputBorder(), labelText: 'Client'),
),
suggestionsCallback: (pattern) async {
print("toto $pattern");
return await model.getSuggestionsClientName(pattern);
},
itemBuilder: (context, suggestion) {
return ListTile(
title: Text(suggestion.toString()),
);
},
transitionBuilder: (context, suggestionsBox, controller) {
print("SuggestionsBox : $suggestionsBox");
print(controller);
return suggestionsBox;
},
onSuggestionSelected: (suggestion) {
print("onclick");
model.typeAheadController.text = suggestion;
},
),
),
);
Or last try, i died my sort method : (this method return item null)
ListView(
children: <Widget>[
SimpleAutocompleteFormField<Employee>(
decoration: InputDecoration(
labelText: 'Person', border: OutlineInputBorder()),
suggestionsHeight: 80.0,
itemBuilder: (context, person) => Padding(
padding: EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(person.firstname,
style: TextStyle(fontWeight: FontWeight.bold)),
Text(person.lastname)
]),
),
onSearch: (search) async => model.employees
.where((person) =>
person.firstname
.toLowerCase()
.contains(search.toLowerCase()) ||
person.lastname
.toLowerCase()
.contains(search.toLowerCase()))
.toList(),
itemFromString: (string) => model.employees.singleWhere(
(person) =>
person.firstname.toLowerCase() ==
string.toLowerCase(),
orElse: () => null),
onFieldSubmitted: (item){
print(item);
},
validator: (person) =>
person == null ? 'Invalid person.' : null,
),
],
),
Solution :
Because in FlutterWeb, this widget is bugged.
For TypeAhead
itemBuilder: (context, suggestion) {
return GestureDetector(
onPanDown: (_) {
model.typeAheadController.text = suggestion;
},
child: Container(
color: Colors.white,
child: ListTile(
title: Text(suggestion.toString()),
),
),
);
},

Why validate() in Form skips some validators (Flutter)?

I am having problems with the validate() function. I can't understand why it skips some validator:(){}. Here is my code:
import 'package:flutter/material.dart';
class TestScreen extends StatefulWidget {
static const routeName = '/test-screen';
#override
_TestScreenState createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen> {
final _form = GlobalKey<FormState>();
Future<void> _saveForm() async {
final isValid = _form.currentState.validate();
if (!isValid) {
return;
}
}
Widget _buildContainer(Widget child) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10),
height: 200,
width: 300,
child: child,
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Test',
style: Theme.of(context).textTheme.title,
),
automaticallyImplyLeading: false,
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Form(
key: _form,
child: ListView(
children: <Widget>[
TextFormField(
initialValue: '',
decoration: InputDecoration(labelText: 'Name'),
validator: (value) {
if (value.isEmpty) {
return 'Insert something';
}
return null;
},
),
TextFormField(
initialValue: '',
decoration: InputDecoration(labelText: 'Number'),
keyboardType: TextInputType.number,
validator: (value) {
if (int.tryParse(value) == null) {
return 'Insert a number';
}
return null;
},
),
SizedBox(height: 20),
_buildContainer(
ListView(
children: <Widget>[],
),
),
Text(
'Text-Test1',
textAlign: TextAlign.center,
),
Slider(
value: 1,
divisions: 3,
min: 0.0,
max: 3.0,
label: 'Test',
onChanged: (newValue) {},
),
SizedBox(
height: 20,
),
Text(
'Text-Test2',
textAlign: TextAlign.center,
),
Slider(
value: 3,
divisions: 4,
min: 0.0,
max: 4.0,
label: 'Nothing2',
onChanged: (newValue) {},
),
SizedBox(
height: 20,
),
Row(
children: <Widget>[
Text('RandomLabel'),
Spacer(),
Container(
width: 100,
child: TextFormField(
initialValue: '',
keyboardType: TextInputType.number,
validator: (value) {
if (int.tryParse(value) == null) {
return 'Insert a number';
}
return null;
},
),
),
],
),
SizedBox(
height: 20,
),
Text(
'Test 2',
textAlign: TextAlign.center,
),
_buildContainer(
ListView.builder(
itemCount: 0,
itemBuilder: (ctx, index) {
return ListTile(
title: Text('hello'),
subtitle: Text('world'),
);
},
),
),
TextFormField(
initialValue: '',
minLines: 4,
maxLines: 4,
decoration: InputDecoration(labelText: 'Text'),
validator: (value) {
if (value.isEmpty) {
return 'Insert something';
}
return null;
},
),
FlatButton.icon(
icon: Icon(Icons.check),
label: Text('Done'),
onPressed: () {
_saveForm();
},
),
],
),
),
),
);
}
}
If I click on Done, it skips the first two TextFormFields and goes to validate the one in the Row. Obviously it is not what I want. How to fix it and validate all the TextFormFields?
Wrapping form fields with ListView is a bad idea: when user scrolls to submit button some inputs are disposed because they are off-screen. You have to replace ListView with Column widget and wrap all form in SingleChildScrollView:
class TestScreen extends StatefulWidget {
static const routeName = '/test-screen';
#override
_TestScreenState createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen> {
final _form = GlobalKey<FormState>();
Future<void> _saveForm() async {
final isValid = _form.currentState.validate();
if (!isValid) {
return;
}
}
Widget _buildContainer(Widget child) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10),
height: 200,
width: 300,
child: child,
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Test',
style: Theme.of(context).textTheme.title,
),
automaticallyImplyLeading: false,
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Form(
key: _form,
child: Column(
children: <Widget>[
TextFormField(
initialValue: '',
decoration: InputDecoration(labelText: 'Name'),
validator: (value) {
if (value.isEmpty) {
return 'Insert something';
}
return null;
},
),
TextFormField(
initialValue: '',
decoration: InputDecoration(labelText: 'Number'),
keyboardType: TextInputType.number,
validator: (value) {
if (int.tryParse(value) == null) {
return 'Insert a number';
}
return null;
},
),
SizedBox(height: 20),
_buildContainer(
ListView(
children: <Widget>[],
),
),
Text(
'Text-Test1',
textAlign: TextAlign.center,
),
Slider(
value: 1,
divisions: 3,
min: 0.0,
max: 3.0,
label: 'Test',
onChanged: (newValue) {},
),
SizedBox(
height: 20,
),
Text(
'Text-Test2',
textAlign: TextAlign.center,
),
Slider(
value: 3,
divisions: 4,
min: 0.0,
max: 4.0,
label: 'Nothing2',
onChanged: (newValue) {},
),
SizedBox(
height: 20,
),
Row(
children: <Widget>[
Text('RandomLabel'),
Spacer(),
Container(
width: 100,
child: TextFormField(
initialValue: '',
keyboardType: TextInputType.number,
validator: (value) {
if (int.tryParse(value) == null) {
return 'Insert a number';
}
return null;
},
),
),
],
),
SizedBox(
height: 20,
),
Text(
'Test 2',
textAlign: TextAlign.center,
),
_buildContainer(
ListView.builder(
itemCount: 0,
itemBuilder: (ctx, index) {
return ListTile(
title: Text('hello'),
subtitle: Text('world'),
);
},
),
),
TextFormField(
initialValue: '',
minLines: 4,
maxLines: 4,
decoration: InputDecoration(labelText: 'Text'),
validator: (value) {
if (value.isEmpty) {
return 'Insert something';
}
return null;
},
),
FlatButton.icon(
icon: Icon(Icons.check),
label: Text('Done'),
onPressed: () {
_saveForm();
},
),
],
),
),
),
),
);
}
}