Flutter Radio Button not showing that it is selected - android

I have three radio buttons so that the user can select their gender. However, only the male radio button is getting highlighted. Even though my console prints other radio buttons when selected, they don't get highlighted on screen. I don't know what to do about it so any help will be really appreciated!
import 'package:flutter/material.dart';
import 'package:vibing/User_Login.dart';
import 'package:vibing/register_user.dart';
import 'package:vibing/register_user.dart';
class UserDetails extends StatefulWidget {
#override
_UserDetailsState createState() => _UserDetailsState();
}
enum Gender{
Male, Female, Others
}
class _UserDetailsState extends State<UserDetails> {
#override
Widget build(BuildContext context) {
final formkey = GlobalKey<FormState>();
String user_name;
String user_age;
int group_value = -1;
Gender _gender = Gender.Male;
final _userName = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
autofocus: false,
keyboardType: TextInputType.text,
validator: (value) {
if(value.isEmpty)
{
return 'Field cannot be empty';
}
return null;
},
onSaved: (value)=> user_name = value,
decoration: InputDecoration(
hintText: 'Enter Name',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
final _userAge = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
keyboardType: TextInputType.number,
autofocus: false,
validator: (value) {
if(value.isEmpty)
{
return 'Field cannot be empty';
}
return null;
},
onSaved: (value)=> user_age = value,
decoration: InputDecoration(
hintText: 'Enter Age',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
final _male = Radio(
value: Gender.Male,
activeColor: Colors.black,
groupValue: _gender,
onChanged: (Gender value){
setState(() {
print(value);
_gender = value;
});
},
);
final _female = Radio(
activeColor: Colors.black,
value: Gender.Female,
groupValue: _gender,
onChanged: (Gender value){
setState(() {
print(value);
_gender = value;
});
},
);
final _others = Radio(
activeColor: Colors.black,
value: Gender.Others,
groupValue: _gender,
onChanged: (Gender value){
setState(() {
print(value);
_gender = value;
});
},
);
return Scaffold(
backgroundColor: Colors.yellow,
body: Container(
key: formkey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Register",
style: TextStyle(fontSize: 64.0, fontWeight: FontWeight.bold),),
SizedBox(height: 50,),
_userName,
SizedBox(height: 20,),
_userAge,
SizedBox(height: 30,),
Row(
crossAxisAlignment: CrossAxisAlignment.center ,
children: <Widget>[
Text(" Gender: ", style: TextStyle(fontSize: 20.0),),
_male,
Text("Male"),
_female,
Text("Female"),
_others,
Text("Others"),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.center ,
children: <Widget>[
FloatingActionButton.extended(
heroTag: "next_button",
backgroundColor: Colors.yellow,
foregroundColor: Colors.black,
onPressed: ()=> Navigator.push(context, MaterialPageRoute(builder: (context)=>UserReg())),
label: Text("Next", style: TextStyle(fontWeight: FontWeight.bold),)
),
SizedBox(width: 230,),
FloatingActionButton.extended(
heroTag: "prev_button",
backgroundColor: Colors.yellow,
foregroundColor: Colors.black,
onPressed: ()=> Navigator.push(context, MaterialPageRoute(builder: (context)=>UserLogin())),
label: Text("Prev", style: TextStyle(fontWeight: FontWeight.bold),)
),
],
),
],
),
),
);
}
}

It doesn't work because you declare state inside the build function. Move it out :
class _UserDetailsState extends State<UserDetails> {
String user_name;
String user_age;
int group_value = -1;
Gender _gender = Gender.Male;
By the way, you can generate widgets for each enum value :
children: <Widget>[
for(var gender in Gender.values)
Radio(
value: gender,
activeColor: Colors.black,
groupValue: _gender,
onChanged: (Gender value){
setState(() {
print(value);
_gender = value;
});
},
);
]
Make sure your minimum SDK version is 2.6.0 or above in the pubspec.yaml

Related

User Entered Data is not saved on Firebase_realtime_database

User Entered Data is not saved on Firebase_realtime_database.I tried making a personal information form . But when I click on submit button , the data entred by user is not saving in firebase(real-time database). What could be error?
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:intl/intl.dart';
import 'package:firebase_database/firebase_database.dart';
class DonorRegistration extends StatefulWidget {
#override
DonorRegistration({Key key}) : super(key: key);
#override
_DonorRegistrationState createState() => _DonorRegistrationState();
}
}
class _DonorRegistrationState extends State<DonorRegistration> {
var data;
bool autoValidate = true;
bool readOnly = false;
bool showSegmentedControl = true;
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
final ValueChanged _onChanged = (val) => print(val);
var currentItemSelected3;
bool disabledropdown = true;
final TextEditingController _nameController = TextEditingController();
String _gender = 'Male';
final TextEditingController _ageController = TextEditingController();
final dbRef = FirebaseDatabase.instance.reference().child("donor");
This is UI area
enter code here
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Color.fromRGBO(1500, 0, 5, 1),
title: Text('Donor Registration'),
),
body: Padding(
padding: const EdgeInsets.all(10),
child: ListView(
children: <Widget>[
Container(
height: 100,
width: 100,
child: CircleAvatar(
backgroundColor: Colors.transparent,
radius: 65.0,
child: Image.asset('lib/assets/logo.png'))),
FormBuilder(
// context,
key: _fbKey,
// autovalidate: true,
readOnly: false,
child: Column(
children: <Widget>[
Text('Personal Information'),
SizedBox(height: 15),
FormBuilderTextField(
attribute: 'Name',
controller: _nameController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
icon: Icon(
Icons.account_circle,
color: Color.fromRGBO(255, 0, 0, 1),
),
labelText: 'Full Name',
hintText: 'Enter Your Full name',
),
validators: [
FormBuilderValidators.required(
errorText: 'This field required')
],
keyboardType: TextInputType.name,
//controller: _nameController,
),
SizedBox(height: 25),
FormBuilderRadioGroup(
attribute: 'radio_group',
decoration: const InputDecoration(
//value: gender,
border: OutlineInputBorder(),
icon: Icon(
Icons.person_pin,
color: Color.fromRGBO(255, 0, 0, 1),
),
labelText: 'Gender'),
onChanged: _onChanged,
options: [
FormBuilderFieldOption(value: 'M', child: Text('Male')),
FormBuilderFieldOption(value: 'F', child: Text('Female')),
FormBuilderFieldOption(value: 'O', child: Text('Other')),
]
.map((_gender) => FormBuilderFieldOption(
value: _gender,
child: Text('$_gender'),
))
.toList(growable: false),
validators: [
FormBuilderValidators.required(
errorText: 'This field required')
],
),
SizedBox(height: 15),
FormBuilderTextField(
attribute: 'age',
// autovalidate: true,
controller: _ageController,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Age',
icon: Icon(
Icons.confirmation_number,
color: Color.fromRGBO(255, 0, 0, 1),
),
),
validators: [
FormBuilderValidators.required(
errorText: 'This field required')
],
keyboardType: TextInputType.number,
),
FormBuilderSwitch(
label: Text('I Accept the tems and conditions'),
attribute: 'accept_terms_switch',
initialValue: true,
onChanged: _onChanged,
),
SizedBox(height: 15),
],
),
),
Row(
children: <Widget>[
Expanded(
child: MaterialButton(
color: Theme.of(context).accentColor,
child: Text(
'Submit',
style: TextStyle(color: Colors.white),
),
onPressed: () {
if (_fbKey.currentState.validate()) {
dbRef.push().set({
"name": _nameController.text,
"age": _ageController.text,
"gender": _gender,
"disease": _diseaseController.text,
"blood_group": _blood,
"body_part": _donate,
"Hospitals": _hospital,
}).then((_) {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text('Successfully Added')));
_ageController.clear();
_nameController.clear();
}).catchError((onError) {
Scaffold.of(context)
.showSnackBar(SnackBar(content: Text(onError)));
});
} else {
print(_fbKey.currentState.value);
print('validation failed');
}
},
),
),
SizedBox(width: 20),
Expanded(
child: MaterialButton(
color: Theme.of(context).accentColor,
child: Text(
'Reset',
style: TextStyle(color: Colors.white),
),
onPressed: () {
_fbKey.currentState.reset();
},
)),
],
),
],
),
),
);
}
#override
void dispose() {
super.dispose();
_ageController.dispose();
_nameController.dispose();
}
}
please tell me what could be errors.

How to validate and update the data from a previous page in flutter?

I wanted to know as to how can I submit the form which will print the user data from a previous page as well as the current page it is in? This will help me further when I am trying to update user data on firestore. I couldn't find a solution hence I would really appreciate whatever help I can get! :)
edit:
For anyone who didn't get what I was trying to say
I have the textfields of First Name, Last name and age in one page for which the user will press on the next button when done entering. In the final registration page which consists of email and password textfields contains the Register button which will register the user. I want to press Register on the final registration page which will print the data entered in the previous page as well as the current page. I wanted to know how can I achieve that so that later on I can update the user data to firestore
previous page
class UserDetails extends StatefulWidget {
#override
_UserDetailsState createState() => _UserDetailsState();
}
enum Gender{
Male, Female, Others
}
class _UserDetailsState extends State<UserDetails> {
String userFirstName;
String userLastName;
String user_age;
int group_value = -1;
Gender _gender = Gender.Male;
final formkeyDetails = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
//final _userProvider = Provider.of<UserProvider>(context);
final _firstName = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
autofocus: false,
keyboardType: TextInputType.text,
/*onChanged: (value){
_userProvider.changeFirstName(value);
},
*/
validator: (value) {
if(value.isEmpty)
{
return 'Field cannot be empty';
}
return null;
},
onSaved: (value)=> userFirstName = value,
decoration: InputDecoration(
hintText: 'Enter First Name',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
final _lastName = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
autofocus: false,
keyboardType: TextInputType.text,
/* onChanged: (value){
_userProvider.changeLastName(value);
}
,
*/
validator: (value) {
if(value.isEmpty)
{
return 'Field cannot be empty';
}
return null;
},
onSaved: (value)=> userLastName = value,
decoration: InputDecoration(
hintText: 'Enter Last Name',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
final _userAge = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
keyboardType: TextInputType.number,
autofocus: false,
/* onChanged: (value){
_userProvider.changeAge(value);
},
*/
validator: (value) {
if(value.isEmpty)
{
return 'Field cannot be empty';
}
return null;
},
onSaved: (value)=> user_age = value,
decoration: InputDecoration(
hintText: 'Enter Age',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
final _male = Radio(
value: Gender.Male,
activeColor: Colors.black,
groupValue: _gender,
onChanged: (Gender value){
setState(() {
print(value);
_gender = value;
});
},
);
final _female = Radio(
activeColor: Colors.black,
value: Gender.Female,
groupValue: _gender,
onChanged: (Gender value){
setState(() {
print(value);
_gender = value;
});
},
);
final _others = Radio(
activeColor: Colors.black,
value: Gender.Others,
groupValue: _gender,
onChanged: (Gender value){
setState(() {
print(value);
_gender = value;
});
},
);
return Scaffold(
backgroundColor: Colors.yellow,
body: Container(
child: Form(
key: formkeyDetails,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Register",
style: TextStyle(fontSize: 64.0, fontWeight: FontWeight.bold),),
SizedBox(height: 50,),
_firstName,
SizedBox(height: 20,),
_lastName,
SizedBox(height: 20,),
_userAge,
SizedBox(height: 30,),
Row(
crossAxisAlignment: CrossAxisAlignment.center ,
children: <Widget>[
Text(" Gender: ", style: TextStyle(fontSize: 20.0),),
_male,
Text("Male"),
_female,
Text("Female"),
_others,
Text("Others"),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.center ,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
FloatingActionButton.extended(
heroTag: "prev_button",
backgroundColor: Colors.yellow,
foregroundColor: Colors.black,
onPressed: ()=> Navigator.push(context, MaterialPageRoute(builder: (context)=>UserLogin())),
label: Text("Prev", style: TextStyle(fontWeight: FontWeight.bold),)
),
FloatingActionButton.extended(
heroTag: "next_button",
backgroundColor: Colors.yellow,
foregroundColor: Colors.black,
onPressed: ()=> Navigator.push(context, MaterialPageRoute(builder: (context)=>UserReg())),
label: Text("Next", style: TextStyle(fontWeight: FontWeight.bold),)
),
],
),
],
),
),
),
);
}
}
Current page (which will print the contents of the previous page as well)
class UserReg extends StatefulWidget {
UserReg({this.auth});
final BaseAuth auth;
#override
State<StatefulWidget> createState() => _UserRegState();
}
class _UserRegState extends State<UserReg> {
final formkey = GlobalKey<FormState>();
static String emailValidator(String value) {
Pattern pattern =
r'^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
RegExp regex = new RegExp(pattern);
if (!regex.hasMatch(value)) {
return 'Email format is invalid';
} else {
return null;
}
}
static String pwdValidator(String value) {
if (value.length <= 6) {
return 'Password must be longer than 8 characters';
} else {
return null;
}
}
bool _validateAndSave()
{
final form2 = formkey.currentState;
final form1 = formkeyDetails.currentState;
if(form2.validate())
{
form.save();
return true;
}
return false;
}
void _validateAndSubmit() async
{
if(_validateAndSave()) {
try {
String userId = await Auth().signUp(rEmail, rPass);
await Auth().sendEmailVerification();
formkey.currentState.reset();
print('Registered! $userId, sent email verification');
}
catch (e) {
print('Error: $e');
}
}
}
final notValidIcon = Icon(
Icons.error,
color: Colors.pink,
);
static String rEmail;
static String rPass;
#override
Widget build(BuildContext context) {
//final userProvider = Provider.of<UserProvider>(context);
final _regEmail = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
keyboardType: TextInputType.emailAddress,
autofocus: false,
validator: (value) {
if(value.isEmpty)
{
return 'Email cannot be empty';
}
else
emailValidator(value);
return null;
},
/*onChanged: (value){
userProvider.changeEmail(value);
},
*/
onSaved: (value)=> rEmail = value,
decoration: InputDecoration(
hintText: 'Enter Email Address',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
final _regpass = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
obscureText: true,
autofocus: false,
validator: pwdValidator,
/*onChanged: (value){
userProvider.changePassword(value);
},
*/
onSaved: (value)=> rPass = value,
decoration: InputDecoration(
hintText: 'Enter password',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
final _confPass = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
obscureText: true,
autofocus: false,
validator: (value){
if(value != rPass)
{
return("Password does not match");
}
return pwdValidator(value);
},
/*
onChanged: (value){
userProvider.changePassword(value);
},
*/
onSaved: (value)=> rPass = value,
decoration: InputDecoration(
hintText: 'Enter password',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
return new Scaffold(
resizeToAvoidBottomInset: true,
backgroundColor: Colors.yellow,
body: Container(
height: MediaQuery.of(context).size.height,
child: Form(
key: formkey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(height: MediaQuery.of(context).size.height *0.2,),
Text('Register',
style:TextStyle(
fontWeight: FontWeight.bold,
fontSize: 64,
),
),
SizedBox(height: 100,),
_regEmail,
SizedBox(height: 20,),
_regpass,
SizedBox(height:30),
//_confRegPass,
SizedBox(height: 30,),
FloatingActionButton.extended(
heroTag: "Register_Button",
backgroundColor: Colors.yellow,
foregroundColor: Colors.black,
onPressed: (){
_validateAndSubmit();
//userProvider.saveUser();
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context)=>UserLogin()));
},
label: Text("Register", style: TextStyle(fontWeight: FontWeight.bold),)
),
SizedBox(height: 20,),
FlatButton(
child: Text('Already Registered? Sign in!'),
onPressed: ()=> Navigator.push(context, MaterialPageRoute(builder: (context)=>UserLogin())) ,
),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
FloatingActionButton.extended(
heroTag: "prev_button1",
backgroundColor: Colors.yellow,
foregroundColor: Colors.black,
onPressed: ()=> Navigator.pop(context), //Navigator.push(context, MaterialPageRoute(builder: (context)=>UserDetails())),
label: Text("Prev", style: TextStyle(fontWeight: FontWeight.bold),)
),
],
),
],
),
),
),
);
}
}
Instead of directly going to the next page, you can validate the form in the current page itself using
onPressed: () {
// Validate returns true if the form is valid, otherwise false.
if (formKey.currentState.validate()) {
//Navigation Logic
}
}
And if you want the data from the previous page then you can refer to https://flutter.dev/docs/cookbook/navigation/passing-data

onSaved of textformfield not being called but the validator is

When I run my program to submit this form, the validator runs and returns with correct error checking however I can not come up with a method to get the onSaved method of the TextFormFields to work. I do not however receive any errors when running the code and the dropdown buttons work and upload to firebase properly. I currently have name set to a print to the logcat for debugging, but it never gets called.
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:connectuproject/authentication.dart';
class player_reg extends StatefulWidget {
player_reg(this.auth);
final BaseAuth auth;
#override
State<StatefulWidget> createState() => new PlayerRegState();
}
class PlayerRegState extends State<player_reg> {
final _formKey = new GlobalKey<FormState>();
String _name = "";
String _age = "";
String _grad = "";
String _highschool = "";
String _city = "";
String _state = "";
String _heightFeet = "";
String _heightInch = "";
String _weight = "";
String _hand = "Right";
String _number = "";
String _email = "";
String _errorMessage = "";
String _position = "Attack";
String _club = "";
bool _isLoading = false;
bool validateAndSave() {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
return true;
}
return false;
}
void validateAndSubmit() async {
setState(() {
_errorMessage = "";
_isLoading = true;
});
print("Auth: " + widget.auth.getUserId());
if (validateAndSave()) {
try {
String _uid = widget.auth.getUserId();
print("_uid: " + _uid + " Name: " + _name);
final databaseReference = Firestore.instance;
await databaseReference.collection("users").document(_uid).setData({
'name': _name,
'age': _age,
'grade': _grad,
'highschool': _highschool,
'state': _state,
'city': _city,
'heightFeet': _heightFeet,
'heightInch': _heightInch,
'weight': _weight,
'hand': _hand,
'position': _position,
'club': _club,
});
}
catch(e){
print(e.message);
}
}
setState(() {
_isLoading = false;
});
}
#override
void initState() {
_errorMessage = "";
_isLoading = false;
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Flutter login demo'),
),
body: Stack(
children: <Widget>[
_showForm(),
_showCircularProgress(),
],
));
}
Widget _showCircularProgress() {
if (_isLoading) {
return Center(child: CircularProgressIndicator());
}
return Container(
height: 0.0,
width: 0.0,
);
}
Widget _showForm() {
return new Container(
padding: EdgeInsets.all(16.0),
child: new Form(
key: _formKey,
child: new ListView(
shrinkWrap: true,
children: <Widget>[
showInstruct(),
showPerson(),
showNameInput(),
showAgeInput(),
showGradInput(),
showHighschoolInput(),
showStateInput(),
showCityInput(),
showPhysical(),
showHeightFeetInput(),
showHeightInchesInput(),
showWeightInput(),
showHandiness(),
showHandinessInput(),
showContact(),
showNumberInput(),
showEmailInput(),
showLacrosse(),
showPosition(),
showPositionInput(),
showClubInput(),
showSubmitButton(),
],
),
),
);
}
Widget showInstruct() {
return new Text(
"Please complete the following ",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontFamily: 'Raleway',
fontSize: 30.0,
fontWeight: FontWeight.bold,
),
);
}
Widget showPerson() {
return new Padding(
padding: const EdgeInsets.fromLTRB(0.0, 50.0, 0.0, 0.0),
child: new Text(
"Personal info: ",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontFamily: 'Raleway',
fontSize: 30.0,
),
));
}
Widget showNameInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
autofocus: false,
decoration: new InputDecoration(
hintText: 'Name',
),
validator: (value) => value.isEmpty ? 'Name can\'t be empty' : null,
onSaved: (String value) => print("saving the name value of " + value),
),
);
}
Widget showAgeInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
maxLength: 2,
autofocus: false,
keyboardType: TextInputType.number,
decoration: new InputDecoration(
hintText: 'Age',
),
validator: (value) => value.isEmpty ? 'Age can\'t be empty' : null,
onSaved: (String value) => _age = value.trim(),
),
);
}
Widget showGradInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
maxLength: 4,
autofocus: false,
keyboardType: TextInputType.number,
decoration: new InputDecoration(
hintText: 'Graduation year',
),
validator: (value) =>
value.isEmpty ? 'Graduation year can\'t be empty' : null,
onSaved: (String value) => _grad = value.trim(),
),
);
}
Widget showHighschoolInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
autofocus: false,
decoration: new InputDecoration(
hintText: 'Highschool',
),
validator: (value) =>
value.isEmpty ? 'Highschool can\'t be empty' : null,
onSaved: (String value) => _highschool = value.trim(),
),
);
}
Widget showStateInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
autofocus: false,
decoration: new InputDecoration(
hintText: 'State',
),
validator: (value) => value.isEmpty ? 'State can\'t be empty' : null,
onSaved: (String value) => _state = value.trim(),
),
);
}
Widget showCityInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 50.0),
child: new TextFormField(
maxLines: 1,
autofocus: false,
decoration: new InputDecoration(
hintText: 'City',
),
validator: (value) => value.isEmpty ? 'State can\'t be empty' : null,
onSaved: (String value) => _city = value.trim(),
),
);
}
Widget showPhysical() {
return new Text(
"Physical info: ",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontFamily: 'Raleway',
fontSize: 30.0,
),
);
}
Widget showHeightFeetInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
maxLength: 1,
autofocus: false,
keyboardType: TextInputType.number,
decoration: new InputDecoration(
hintText: 'Height(feet)',
),
validator: (value) => value.isEmpty ? 'Height can\'t be empty' : null,
onSaved: (String value) => _heightFeet = value.trim(),
),
);
}
Widget showHeightInchesInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
maxLength: 2,
autofocus: false,
keyboardType: TextInputType.number,
decoration: new InputDecoration(
hintText: 'Height(inches)',
),
validator: (value) => value.isEmpty ? 'Height can\'t be empty' : null,
onSaved: (String value) => _heightInch = value.trim(),
),
);
}
Widget showWeightInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
maxLength: 3,
autofocus: false,
keyboardType: TextInputType.number,
decoration: new InputDecoration(
hintText: 'weight(lbs)',
),
validator: (value) => value.isEmpty ? 'Weight can\'t be empty' : null,
onSaved: (String value) => _weight = value.trim(),
),
);
}
Widget showHandiness() {
return new Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: Text(
"Handiness:",
style: TextStyle(fontSize: 20),
),
);
}
Widget showHandinessInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 0.0),
child: Container(
width: double.infinity,
child: new DropdownButton<String>(
isExpanded: true,
value: _hand,
elevation: 16,
underline: Container(
height: 2,
),
onChanged: (String newValue) {
setState(() {
_hand = newValue;
});
},
items: <String>['Right','Left']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)),
);
}
Widget showContact() {
return new Text(
"Contact info: ",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontFamily: 'Raleway',
fontSize: 30.0,
),
);
}
Widget showNumberInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
autofocus: false,
keyboardType: TextInputType.phone,
decoration: new InputDecoration(
hintText: 'Phone Number',
),
validator: (value) => value.isEmpty ? 'Number can\'t be empty' : null,
onSaved: (String value) => _number = value.trim(),
),
);
}
Widget showEmailInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 50.0),
child: new TextFormField(
maxLines: 1,
autofocus: false,
keyboardType: TextInputType.emailAddress,
decoration: new InputDecoration(
hintText: 'Email',
),
validator: (value) => value.isEmpty ? 'Not a valid Email' : null,
onSaved: (String value) => _email = value.trim(),
),
);
}
Widget showLacrosse() {
return new Text(
"Lacrosse info: ",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontFamily: 'Raleway',
fontSize: 30.0,
),
);
}
Widget showPosition() {
return new Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: Text(
"Position:",
style: TextStyle(fontSize: 20),
));
}
Widget showPositionInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 0.0),
child: Container(
width: double.infinity,
child: new DropdownButton<String>(
isExpanded: true,
value: _position,
elevation: 16,
underline: Container(
height: 2,
),
onChanged: (String newValue) {
setState(() {
_position = newValue;
});
},
items: <String>[
'Attack',
'Defense',
'Face-off',
'Goalie',
'Long Stick Midfield',
'Midfield'
].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)),
);
}
Widget showClubInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 50.0),
child: new TextFormField(
maxLines: 1,
autofocus: false,
decoration: new InputDecoration(
hintText: 'Club Team',
),
onSaved: (String value) => _club = value.trim(),
),
);
}
Widget showSubmitButton() {
return new Padding(
padding: EdgeInsets.fromLTRB(0.0, 45.0, 0.0, 25.0),
child: SizedBox(
height: 40.0,
child: new RaisedButton(
elevation: 5.0,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0)),
color: Colors.blue,
child: new Text("Submit"),
onPressed: validateAndSubmit,
),
));
}
}
enter code here
After a few days of hard effort I realized the form fields were clearing when I scrolled down the screen. The solution was to wrap the entire field in a SingleChildScrollView and replace my list view with a column.

Flutter dart: How to separate the space between Text and TextField and also bring together RadioListTile?

I'm learning Flutter. I have a problem (see image below). I would like to separate the space between Text "sex" and TextField "name". I would also like to bring together RadioListTile, they are very separate. Is it possible to do that? Follow my code
class _AlertDialogWidgetState extends State<AlertDialogWidget> {
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: ListBody(
children: <Widget>[
TextField(
autofocus: true,
decoration: InputDecoration(
contentPadding: new EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0),
border: OutlineInputBorder(), hintText: "New user"),
onChanged: (text) => widget.name = text,
),
Text(
'Sex',
textAlign: TextAlign.left,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontWeight: FontWeight.bold),
),
RadioListTile(
title: Text("Female"),
value: "female",
groupValue: widget.sex,
onChanged: (String value) {
setState(() {
widget.sex = value;
});
},
),
RadioListTile(
title: Text("Male"),
value: "male",
groupValue: widget.sex,
onChanged: (String value) {
setState(() {
widget.sex = value;
});
},
),
RadioListTile(
title: Text("Other"),
value: "other",
groupValue: widget.sex,
onChanged: (String value) {
setState(() {
widget.sex = value;
});
},
),
],
),
);
}
}
Wrap your TextField with Padding to put more space between TextField and Text like this:
Padding(
padding: EdgeInsets.only(top: 15),
child: Text(
'Sex',
textAlign: TextAlign.left,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontWeight: FontWeight.bold),
),
),
For RadioListTile, you cannot change the padding of radio, but you could use Radio wrapped with ListTile and set its alignment to have it closer to the title:
ListTile(
title: Align(
child: new Text("Female"),
alignment: Alignment(-1.2, 0),
),
leading: Radio(
value: "female",
groupValue: 'F',
onChanged: (String value) {
setState(() {
widget.sex = value;
});
},
),
)

Datepicker inside stepper

So I'm actually pretty new with flutter and this is my first project. Everything went well, until this problem came up.
Recently, I added a stepperBody into my page and in one of the steps there should be a datePicker integrated. Unfortunately, I can't really resolve the problem that is coming up.
I'm constantly getting an "Only static members can be accessed in initializers." error.
Help is appreciated.
I'm using the flutter_datetime_picker plugin.
Here's my code:
class StepperBody extends StatefulWidget {
#override
_StepperBodyState createState() => _StepperBodyState();
}
class _StepperBodyState extends State<StepperBody> {
String _date = "Not set";
int currStep = 0;
static var _focusNode = FocusNode();
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
static MyData data = MyData();
#override
void initState() {
super.initState();
_focusNode.addListener(() {
setState(() {});
print('Has focus: $_focusNode.hasFocus');
});
}
List<Step> steps = [
Step(
title: const Text('Name',
style: TextStyle(
fontFamily: 'Maax',
fontSize: 20,
),),
//subtitle: const Text('Enter your name'),
isActive: true,
//state: StepState.error,
state: StepState.indexed,
content: Form(
key: formKeys[0],
child: Column(
children: <Widget>[
TextFormField(
style: TextStyle(
fontFamily: 'Maax',
fontWeight: FontWeight.w500,
),
focusNode: _focusNode,
keyboardType: TextInputType.text,
autocorrect: false,
onSaved: (String value) {
data.title = value;
},
maxLines: 1,
//initialValue: 'Aseem Wangoo',
validator: (value) {
if (value.isEmpty || value.length < 1) {
return 'Please enter title';
}
},
decoration: InputDecoration(
labelText: 'What is the name of the test?',
hintText: 'Enter a name',
//filled: true,
icon: const FaIcon(FontAwesomeIcons.signature),
labelStyle:
TextStyle(decorationStyle: TextDecorationStyle.solid, fontFamily: 'Maax', fontWeight: FontWeight.w500)),
),
],
),
)),
Step(
title: const Text('Date'),
//subtitle: const Text('Subtitle'),
isActive: true,
//state: StepState.editing,
state: StepState.indexed,
content: Form(
key: formKeys[1],
child: Column(
children: <Widget>[
RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0)),
elevation: 4.0,
onPressed: () {
DatePicker.showDatePicker(context,
theme: DatePickerTheme(
containerHeight: 210.0,
),
showTitleActions: true,
minTime: DateTime(2000, 1, 1),
maxTime: DateTime(2022, 12, 31), onConfirm: (date) {
print('confirm $date');
_date = '${date.year} - ${date.month} - ${date.day}';
setState(() {});
}, currentTime: DateTime.now(), locale: LocaleType.en);
},
child: Container(
alignment: Alignment.center,
height: 50.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: <Widget>[
Container(
child: Row(
children: <Widget>[
Icon(
Icons.date_range,
size: 18.0,
color: Colors.teal,
),
Text(
" $_date",
style: TextStyle(
color: Colors.teal,
fontWeight: FontWeight.bold,
fontSize: 18.0),
),
],
),
)
],
),
Text(
" Change",
style: TextStyle(
color: Colors.teal,
fontWeight: FontWeight.bold,
fontSize: 18.0),
),
],
),
),
color: Colors.white,
),
TextFormField(
keyboardType: TextInputType.phone,
autocorrect: false,
validator: (value) {
if (value.isEmpty || value.length < 10) {
return 'Please enter valid number';
}
},
onSaved: (String value) {
data.days = value;
},
maxLines: 1,
decoration: InputDecoration(
labelText: 'Enter your number',
hintText: 'Enter a number',
icon: const Icon(Icons.phone),
labelStyle:
TextStyle(decorationStyle: TextDecorationStyle.solid)),
),
],
),
)),
Step(
title: const Text('Email'),
// subtitle: const Text('Subtitle'),
isActive: true,
state: StepState.indexed,
// state: StepState.disabled,
content: Form(
key: formKeys[2],
child: Column(
children: <Widget>[
TextFormField(
keyboardType: TextInputType.emailAddress,
autocorrect: false,
validator: (value) {
if (value.isEmpty || !value.contains('#')) {
return 'Please enter valid email';
}
},
onSaved: (String value) {
data.words = value;
},
maxLines: 1,
decoration: InputDecoration(
labelText: 'Enter your email',
hintText: 'Enter a email address',
icon: const Icon(Icons.email),
labelStyle:
TextStyle(decorationStyle: TextDecorationStyle.solid)),
),
],
),
)),
Step(
title: const Text('Age'),
// subtitle: const Text('Subtitle'),
isActive: true,
state: StepState.indexed,
content: Form(
key: formKeys[3],
child: Column(
children: <Widget>[
TextFormField(
keyboardType: TextInputType.number,
autocorrect: false,
validator: (value) {
if (value.isEmpty || value.length > 2) {
return 'Please enter valid age';
}
},
maxLines: 1,
onSaved: (String value) {
data.rep = value;
},
decoration: InputDecoration(
labelText: 'Enter your age',
hintText: 'Enter age',
icon: const Icon(Icons.explicit),
labelStyle:
TextStyle(decorationStyle: TextDecorationStyle.solid)),
),
],
),
)),
// Step(
// title: const Text('Fifth Step'),
// subtitle: const Text('Subtitle'),
// isActive: true,
// state: StepState.complete,
// content: const Text('Enjoy Step Fifth'))
];
#override
Widget build(BuildContext context) {
void showSnackBarMessage(String message,
[MaterialColor color = Colors.red]) {
Scaffold
.of(context)
.showSnackBar( SnackBar(content: Text(message)));
}
void _submitDetails() {
final FormState formState = _formKey.currentState;
if (!formState.validate()) {
showSnackBarMessage('Please enter correct data');
} else {
formState.save();
print("Name: ${data.title}");
print("Phone: ${data.days}");
print("Email: ${data.words}");
print("Age: ${data.rep}");
showDialog(
context: context,
child: AlertDialog(
title: Text("Details"),
//content: Text("Hello World"),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text("Name : " + data.title),
Text("Phone : " + data.days),
Text("Email : " + data.words),
Text("Age : " + data.rep),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
));
}
}
return Container(
child: Form(
key: _formKey,
child: ListView(children: <Widget>[
Stepper(
steps: steps,
type: StepperType.vertical,
currentStep: this.currStep,
onStepContinue: () {
setState(() {
if(formKeys[currStep].currentState.validate()) {
if (currStep < steps.length - 1) {
currStep = currStep + 1;
} else {
currStep = 0;
}
}
// else {
// Scaffold
// .of(context)
// .showSnackBar( SnackBar(content: Text('$currStep')));
// if (currStep == 1) {
// print('First Step');
// print('object' + FocusScope.of(context).toStringDeep());
// }
// }
});
},
onStepCancel: () {
setState(() {
if (currStep > 0) {
currStep = currStep - 1;
} else {
currStep = 0;
}
});
},
onStepTapped: (step) {
setState(() {
currStep = step;
});
},
),
RaisedButton(
child: Text(
'Save details',
style: TextStyle(color: Colors.white),
),
onPressed: _submitDetails,
color: Colors.blue,
),
]),
));
}
}
You can copy paste run full code below
You can move steps definition to build to avoid Only static members can be accessed in initializers and allow _date to change after setState
To avoid known issue of flutter_datetime_picker, I use this git
flutter_datetime_picker:
git:
url: https://github.com/derohimat/flutter_datetime_picker.git
code snippet
#override
Widget build(BuildContext context) {
steps = [
Step(
working demo
full code
import 'package:flutter/material.dart';
import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
class MyData {
String title;
String days;
String words;
String rep;
MyData({this.title, this.days, this.words, this.rep});
}
class StepperBody extends StatefulWidget {
#override
_StepperBodyState createState() => _StepperBodyState();
}
class _StepperBodyState extends State<StepperBody> {
String _date = "Not set";
int currStep = 0;
static var _focusNode = FocusNode();
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
static MyData data = MyData();
List<GlobalKey<FormState>> formKeys = [
GlobalKey<FormState>(),
GlobalKey<FormState>(),
GlobalKey<FormState>(),
GlobalKey<FormState>()
];
List<Step> steps = [];
#override
void initState() {
super.initState();
_focusNode.addListener(() {
setState(() {});
print('Has focus: $_focusNode.hasFocus');
});
}
#override
Widget build(BuildContext context) {
steps = [
Step(
title: const Text(
'Name',
style: TextStyle(
fontFamily: 'Maax',
fontSize: 20,
),
),
//subtitle: const Text('Enter your name'),
isActive: true,
//state: StepState.error,
state: StepState.indexed,
content: Form(
key: formKeys[0],
child: Column(
children: <Widget>[
TextFormField(
style: TextStyle(
fontFamily: 'Maax',
fontWeight: FontWeight.w500,
),
focusNode: _focusNode,
keyboardType: TextInputType.text,
autocorrect: false,
onSaved: (String value) {
data.title = value;
},
maxLines: 1,
//initialValue: 'Aseem Wangoo',
validator: (value) {
if (value.isEmpty || value.length < 1) {
return 'Please enter title';
}
},
decoration: InputDecoration(
labelText: 'What is the name of the test?',
hintText: 'Enter a name',
//filled: true,
icon: Icon(Icons.add),
labelStyle: TextStyle(
decorationStyle: TextDecorationStyle.solid,
fontFamily: 'Maax',
fontWeight: FontWeight.w500)),
),
],
),
)),
Step(
title: const Text('Date'),
//subtitle: const Text('Subtitle'),
isActive: true,
//state: StepState.editing,
state: StepState.indexed,
content: Form(
key: formKeys[1],
child: Column(
children: <Widget>[
RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0)),
elevation: 4.0,
onPressed: () {
DatePicker.showDatePicker(context,
theme: DatePickerTheme(
containerHeight: 210.0,
),
showTitleActions: true,
minTime: DateTime(2000, 1, 1),
maxTime: DateTime(2022, 12, 31), onConfirm: (date) {
print('confirm $date');
_date = '${date.year} - ${date.month} - ${date.day}';
print('date ${_date}');
setState(() {});
}, currentTime: DateTime.now(), locale: LocaleType.en);
},
child: Container(
alignment: Alignment.center,
height: 50.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: <Widget>[
Container(
child: Row(
children: <Widget>[
Icon(
Icons.date_range,
size: 18.0,
color: Colors.teal,
),
Text(
" $_date",
style: TextStyle(
color: Colors.teal,
fontWeight: FontWeight.bold,
fontSize: 18.0),
),
],
),
)
],
),
Text(
" Change",
style: TextStyle(
color: Colors.teal,
fontWeight: FontWeight.bold,
fontSize: 18.0),
),
],
),
),
color: Colors.white,
),
TextFormField(
keyboardType: TextInputType.phone,
autocorrect: false,
validator: (value) {
if (value.isEmpty || value.length < 10) {
return 'Please enter valid number';
}
},
onSaved: (String value) {
data.days = value;
},
maxLines: 1,
decoration: InputDecoration(
labelText: 'Enter your number',
hintText: 'Enter a number',
icon: const Icon(Icons.phone),
labelStyle: TextStyle(
decorationStyle: TextDecorationStyle.solid)),
),
],
),
)),
Step(
title: const Text('Email'),
// subtitle: const Text('Subtitle'),
isActive: true,
state: StepState.indexed,
// state: StepState.disabled,
content: Form(
key: formKeys[2],
child: Column(
children: <Widget>[
TextFormField(
keyboardType: TextInputType.emailAddress,
autocorrect: false,
validator: (value) {
if (value.isEmpty || !value.contains('#')) {
return 'Please enter valid email';
}
},
onSaved: (String value) {
data.words = value;
},
maxLines: 1,
decoration: InputDecoration(
labelText: 'Enter your email',
hintText: 'Enter a email address',
icon: const Icon(Icons.email),
labelStyle: TextStyle(
decorationStyle: TextDecorationStyle.solid)),
),
],
),
)),
Step(
title: const Text('Age'),
// subtitle: const Text('Subtitle'),
isActive: true,
state: StepState.indexed,
content: Form(
key: formKeys[3],
child: Column(
children: <Widget>[
TextFormField(
keyboardType: TextInputType.number,
autocorrect: false,
validator: (value) {
if (value.isEmpty || value.length > 2) {
return 'Please enter valid age';
}
},
maxLines: 1,
onSaved: (String value) {
data.rep = value;
},
decoration: InputDecoration(
labelText: 'Enter your age',
hintText: 'Enter age',
icon: const Icon(Icons.explicit),
labelStyle: TextStyle(
decorationStyle: TextDecorationStyle.solid)),
),
],
),
)),
// Step(
// title: const Text('Fifth Step'),
// subtitle: const Text('Subtitle'),
// isActive: true,
// state: StepState.complete,
// content: const Text('Enjoy Step Fifth'))
];
void showSnackBarMessage(String message,
[MaterialColor color = Colors.red]) {
Scaffold.of(context).showSnackBar(SnackBar(content: Text(message)));
}
void _submitDetails() {
final FormState formState = _formKey.currentState;
if (!formState.validate()) {
showSnackBarMessage('Please enter correct data');
} else {
formState.save();
print("Name: ${data.title}");
print("Phone: ${data.days}");
print("Email: ${data.words}");
print("Age: ${data.rep}");
showDialog(
context: context,
child: AlertDialog(
title: Text("Details"),
//content: Text("Hello World"),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text("Name : " + data.title),
Text("Phone : " + data.days),
Text("Email : " + data.words),
Text("Age : " + data.rep),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
));
}
}
return Container(
child: Form(
key: _formKey,
child: ListView(children: <Widget>[
Stepper(
steps: steps,
type: StepperType.vertical,
currentStep: this.currStep,
onStepContinue: () {
setState(() {
if (formKeys[currStep].currentState.validate()) {
if (currStep < steps.length - 1) {
currStep = currStep + 1;
} else {
currStep = 0;
}
}
// else {
// Scaffold
// .of(context)
// .showSnackBar( SnackBar(content: Text('$currStep')));
// if (currStep == 1) {
// print('First Step');
// print('object' + FocusScope.of(context).toStringDeep());
// }
// }
});
},
onStepCancel: () {
setState(() {
if (currStep > 0) {
currStep = currStep - 1;
} else {
currStep = 0;
}
});
},
onStepTapped: (step) {
setState(() {
currStep = step;
});
},
),
RaisedButton(
child: Text(
'Save details',
style: TextStyle(color: Colors.white),
),
onPressed: _submitDetails,
color: Colors.blue,
),
]),
));
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: "test",),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(child: StepperBody()),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

Categories

Resources