I’m building a form that signs up the user on Firebase, and where the ElevatedButton either displays "CREATE YOUR ACCOUNT" or a CircularProgressIndicator, based on the state of isLoading. Yet, the button’s child doesn’t change based on isLoading.
The states does change — I’m printing out isLoading in the middle of my onPressed methode, and I do see it as true.
Why isn’t the button changing its child?
import 'package:flutter/material.dart';
import 'package:tedy/components/custom_text_form_field.dart';
import 'package:tedy/components/custom_wrapper.dart';
class EmployerOnboardingOneView extends StatefulWidget {
const EmployerOnboardingOneView({Key? key}) : super(key: key);
@override
State<EmployerOnboardingOneView> createState() =>
_EmployerOnboardingOneViewState();
}
class _EmployerOnboardingOneViewState extends State<EmployerOnboardingOneView> {
var firstNameController = TextEditingController();
var lastNameController = TextEditingController();
var emailController = TextEditingController();
var passwordController = TextEditingController();
var passwordConfirmController = TextEditingController();
bool isLoading = false;
@override
Widget build(BuildContext context) {
var screenWidth = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
centerTitle: true,
title: SizedBox(
height: 50,
child: Image.asset(
'assets/images/tedy_logo_color.png',
filterQuality: FilterQuality.high,
),
),
),
body: CustomWrapper(
maxWidth: 400,
children: [
Text(
'Create a Tedy account for your company',
style: Theme.of(context).textTheme.headline3,
textAlign: TextAlign.center,
),
const SizedBox(
height: 20,
),
CustomTextFormField(
controller: firstNameController, label: 'First Name'),
const SizedBox(
height: 20,
),
CustomTextFormField(
controller: lastNameController, label: 'Last Name'),
const SizedBox(
height: 20,
),
CustomTextFormField(controller: emailController, label: 'Email'),
const SizedBox(
height: 20,
),
CustomTextFormField(
controller: passwordController,
isPassword: true,
label: 'Password'),
const SizedBox(
height: 20,
),
CustomTextFormField(
controller: passwordConfirmController,
isPassword: true,
label: 'Confirm your password'),
const SizedBox(
height: 20,
),
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Theme.of(context).primaryColor),
onPressed: () async {
setState(() {
isLoading = true;
});
if (passwordController.text != passwordConfirmController.text) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Passwords must match'),
backgroundColor: Colors.red,
),
);
} else {
try {
FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: emailController.text,
password: passwordController.text)
.then((value) {
Navigator.pushNamedAndRemoveUntil(
context, '/', (route) => false);
});
print(isLoading);
} on FirebaseAuthException catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(e.message != null
? e.message as String
: 'There was an error.'),
backgroundColor: Colors.red,
),
);
}
}
setState(() {
isLoading = false;
});
},
child: isLoading
? const SizedBox(
width: 30,
height: 30,
child: CircularProgressIndicator(
color: Colors.white,
),
)
: const Text('CREATE YOUR ACCOUNT'),
),
)
],
),
);
}
}
>Solution :
You are using then for the future. so the last isLoading = false; executed when you pressed the button. You can change state inside .then instead of end. Also you can add inside FirebaseAuthException. make sure to remove last isLoading = false;
FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: emailController.text,
password: passwordController.text)
.then((value) {
setState(() {
isLoading = false;
});
Navigator.pushNamedAndRemoveUntil(
context, '/', (route) => false);
});