I'm working on a Flutter app where I need to implement a password field within a TextFormField
that includes a visibility toggle (eye icon) to show/hide the password. Despite attempting to integrate this feature, I'm facing challenges with passing the visibility state to my custom TextFormField
widget.
Here's what I currently have and what I aim to achieve (with images illustrating my design goal):
Current Design:
Target Design with Visibility Toggle:
Relevant Code Snippets:
Profile.dart snippet showcasing the password TextFormField
:
profile.dart
class _ProfileState extends State<Profile> {
Auth _auth = Auth.signUp;
final _signUpFormKey = GlobalKey<FormState>();
final _signInFormKey = GlobalKey<FormState>();
final TextEditingController _emailController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
final TextEditingController _nameController = TextEditingController();
@override
void dispose() {
super.dispose();
_emailController.dispose();
_passwordController.dispose();
_nameController.dispose();
}
bool isHiddenPassword = true;
...child: Form(
key: _signUpFormKey,
...CustomTextField(
controller: _passwordController,
hintText: 'Password',
style: GoogleFonts.nunito(
color: const Color(0xff3B3B3B),
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w500,
fontSize: 20.0,
),
),
custom_textfield.dart
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class CustomTextField extends StatefulWidget {
final TextEditingController controller;
final String hintText;
final TextStyle style;
const CustomTextField({
Key? key,
required this.controller,
required this.hintText,
required this.style,
}) : super(key: key);
@override
State<CustomTextField> createState() => _CustomTextFieldState();
}
class _CustomTextFieldState extends State<CustomTextField> {
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: TextFormField(
style: GoogleFonts.nunito(
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w500,
fontSize: 20.0,
),
controller: widget.controller,
decoration: InputDecoration(
hintText: widget.hintText,
border: const OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xff3B3B3B),
)),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xff3B3B3B),
),
),
),
validator: (val) {
return null;
},
),
);
}
}
This is my toggle:
bool isHiddenPassword = true;
TextField(
obscureText: isHiddenPassword,
cursorColor: const Color(0xff3B3B3B),
decoration: InputDecoration(
hintText: '8+ Characters',
hintStyle: const TextStyle(
fontSize: 20.0, color: Color(0xffD7D7D7)),
suffixIcon: InkWell(
onTap: _togglePasswordView,
child: isHiddenPassword
? const Icon(
Icons.visibility_off,
color: Color(0xff3B3B3B),
)
: const Icon(
Icons.visibility,
color: Colors.grey,
),
),
enabledBorder: const UnderlineInputBorder(
borderSide:
BorderSide(color: Color(0xffD7D7D7)),
),
focusedBorder: const UnderlineInputBorder(
borderSide:
BorderSide(color: Color(0xffD7D7D7)),
),
),
style: const TextStyle(
fontSize: 20,
decoration: TextDecoration.none,
decorationStyle: TextDecorationStyle.dotted,
decorationColor: Color(0xffF6F6F6),
fontStyle: FontStyle.normal,
fontWeight: FontWeight.normal,
color: Color.fromRGBO(59, 59, 59, 1),
),
),
void _togglePasswordView() {
setState(() {
isHiddenPassword = !isHiddenPassword;
});
}
My Question:
How can I ensure the visibility toggle (eye icon) properly toggles the visibility of the password in my custom TextFormField
widget? I'm having difficulty passing the isHiddenPassword state and the _togglePasswordView
function to control the visibility from my Profile
widget to the custom CustomTextField
widget.
Any guidance or examples on how to achieve this functionality would be greatly appreciated. Thank you in advance for your help!
While isHiddenPassword
is just needed and update on the _CustomTextFieldState
you dont need to worry about parent widget. But if you like to use it for all textFiled, It would be better to add a widget params to check if it password type or not. I am setting default is false.
class CustomTextField extends StatefulWidget {
final TextEditingController controller;
final String hintText;
final TextStyle style;
final bool isPasswordFiled;
const CustomTextField({
Key? key,
required this.controller,
required this.hintText,
required this.style,
this.isPasswordFiled = false,
}) : super(key: key);
@override
State<CustomTextField> createState() => _CustomTextFieldState();
}
class _CustomTextFieldState extends State<CustomTextField> {
bool isHiddenPassword = true;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: TextFormField(
obscureText: widget.isPasswordFiled && isHiddenPassword,
style: GoogleFonts.nunito(
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w500,
fontSize: 20.0,
),
controller: widget.controller,
decoration: InputDecoration(
suffixIcon: widget.isPasswordFiled
? InkWell(
onTap: () {
setState(() {
isHiddenPassword = !isHiddenPassword;
});
},
child: isHiddenPassword
? const Icon(
Icons.visibility_off,
color: Color(0xff3B3B3B),
)
: const Icon(
Icons.visibility,
color: Colors.grey,
),
)
: null,
hintText: widget.hintText,
border: const OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xff3B3B3B),
)),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xff3B3B3B),
),
),
),
validator: (val) {
return null;
},
),
);
}
}