I'm creating an account creation page. It consists of some text fields, checkboxes, and an elevated button.
In the image above, That button is enabled (clickable) only if the above fields are filled and the checkboxes are enabled. Otherwise, it should be disabled (unclickable).
How to achieve this?
Code:
Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 35),
child: Container(
width: 310,
child: TextFormField(
controller: _firstnameController,
decoration: InputDecoration(
label: RichText(
text: TextSpan(
text: 'First Name',
style: GoogleFonts.poppins(
color: Color(0xffc1c1c1),
fontSize: 17,
letterSpacing: 0.4),
children: const [
TextSpan(
text: ' *',
style: TextStyle(
color: Colors.red,
fontSize: 21,
)),
]),
),
),
validator: (value){
if(value!.isEmpty){
return 'This field is required';
}
return null;
},
),
),
),
Padding(
padding: const EdgeInsets.only(top: 20),
child: Container(
width: 310,
child: TextFormField(
controller: _lastnameController,
decoration: InputDecoration(
label: RichText(
text: TextSpan(
text: 'Last Name',
style: GoogleFonts.poppins(
color: Color(0xffc1c1c1),
fontSize: 17,
letterSpacing: 0.4),
children: const [
TextSpan(
text: ' *',
style: TextStyle(
color: Colors.red,
fontSize: 21,
)),
]),
),
),
validator: (value){
if(value!.isEmpty){
return 'This field is required';
}
return null;
},
),
),
),
Padding(
padding: const EdgeInsets.only(top: 20),
child: Container(
width: 310,
child: TextFormField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
label: RichText(
text: TextSpan(
text: 'Enter Your Email',
style: GoogleFonts.poppins(
color: Color(0xffc1c1c1),
fontSize: 17,
letterSpacing: 0.4),
children: const [
TextSpan(
text: ' *',
style: TextStyle(
color: Colors.red,
fontSize: 21,
)),
]),
),
),
validator: (value){
if(value!.isEmpty){
return 'This field is required';
}
if(!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)){
return 'Enter a valid email';
}
return null;
},
),
),
),
Padding(
padding: const EdgeInsets.only(top: 20),
child: Container(
width: 310,
child: TextFormField(
controller: _passwordController,
obscureText: passwordVisible,
decoration: InputDecoration(
label: RichText(
text: TextSpan(
text: 'Enter Your Password',
style: GoogleFonts.poppins(
color: Color(0xffc1c1c1),
fontSize: 17,
letterSpacing: 0.4),
children: const [
TextSpan(
text: ' *',
style: TextStyle(
color: Colors.red,
fontSize: 21,
)),
]),
),
suffixIcon: IconButton(
icon: Icon(passwordVisible ? Icons.visibility_off : Icons.visibility,
color: Color.fromARGB(255, 187, 187, 187),
size: 25,
),
onPressed: (){
setState(() {
passwordVisible = !passwordVisible;
});
},
),
),
validator: (value){
if(value!.isEmpty){
return 'Please enter your password';
}
return null;
},
),
),
),
Padding(
padding: const EdgeInsets.only(top: 30),
child: CheckboxListTile(
title: RichText(
text: TextSpan(
children: [
TextSpan(
text: 'I have read and agree to the',
style: GoogleFonts.poppins(
color: Color(0xff000000),
fontSize: 15,
letterSpacing: 0.4,
),
),
TextSpan(
text: ' Privacy Policy.',
style: GoogleFonts.poppins(
color: Colors.blue,
fontSize: 15,
letterSpacing: 0.4,
),
recognizer: TapGestureRecognizer()
..onTap = () {
launchUrl(Uri.parse('https://toy-zania.com/pages/privacy-policy') );
}
),
]),
),
value: _isChecked0,
onChanged: (bool? newValue) {
setState(() {
_isChecked0 = newValue ?? false;
});
},
activeColor: Color(0xff82b235),
controlAffinity: ListTileControlAffinity.leading,
),
),
Padding(
padding: const EdgeInsets.only(top: 10),
child: CheckboxListTile(
title: RichText(
text: TextSpan(
children: [
TextSpan(
text: 'I have read and agree to the',
style: GoogleFonts.poppins(
color: Color(0xff000000),
fontSize: 15,
letterSpacing: 0.4,
),
),
TextSpan(
text: ' Terms & Conditions ',
style: GoogleFonts.poppins(
color: Colors.blue,
fontSize: 15,
letterSpacing: 0.4,
),
recognizer: TapGestureRecognizer()
..onTap = () {
launchUrl(Uri.parse('https://toy-zania.com/pages/term') );
}
),
TextSpan(
text: '& Warranty.',
style: GoogleFonts.poppins(
color: Color(0xff000000),
fontSize: 15,
letterSpacing: 0.4,
),
),
]),
),
value: _isChecked1,
onChanged: (bool? newValue) {
setState(() {
_isChecked1 = newValue ?? false;
});
},
activeColor: Color(0xff82b235),
controlAffinity: ListTileControlAffinity.leading,
),
),
Padding(
padding: const EdgeInsets.only(top: 40),
child: SizedBox(
width: 320, // <-- match_parent
height: 45,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
foregroundColor: Color(0xffe5e5e5),
backgroundColor: Color(0xff734FE0),
),
onPressed: () {
createAccount();
},
child: Text('CREATE ACCOUNT',
style: GoogleFonts.poppins(
fontSize: 16,
letterSpacing: 1,
)),
),
),
),
You can listen to the TextEditingController
s and others button/objects that will be responsible to control the button state. Here is an example
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final TextEditingController _controller = TextEditingController();
final TextEditingController _controller2 = TextEditingController();
bool isCheck = false;
bool enableButton = false;
void _checkFields() {
enableButton =
_controller.text.isNotEmpty && _controller2.text.isNotEmpty && isCheck;
setState(() {});
}
@override
void initState() {
super.initState();
_controller.addListener(_checkFields);
_controller2.addListener(_checkFields);
}
//dispose them
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: _controller,
),
TextField(
controller: _controller2,
),
Checkbox(
value: isCheck,
onChanged: (value) {
setState(() {
isCheck = value ?? false;
});
_checkFields();
}),
ElevatedButton(
onPressed: enableButton ? () {} : null,
child: const Text('Submit'),
),
],
),
),
);
}
}