How to show/hide password in TextFormField?
Currently I have my password TextFormField
like this:
TextFormField(
decoration: const InputDecoration(
labelText: 'Password',
icon: const Padding(
padding: const EdgeInsets.only(top: 15.0),
child: const Icon(Icons.lock),
)),
validator: (val) => val.length < 6 ? 'Password too short.' : null,
onSaved: (val) => _password = val,
obscureText: true,
);
I want a button like interaction which will make password visible and invisible. Can I do it inside TextFormField
? Or I will have to make a Stack
widget to get my required UI. And how will the condition be made regarding obscureText
true/false?
I have created a solution as per @Hemanth Raj but in a more robust way.
First declare a bool
variable _passwordVisible
.
Initiate _passwordVisible
to false
in initState()
@override
void initState() {
_passwordVisible = false;
}
Following is the TextFormField
widget :
TextFormField(
keyboardType: TextInputType.text,
controller: _userPasswordController,
obscureText: !_passwordVisible,//This will obscure text dynamically
decoration: InputDecoration(
labelText: 'Password',
hintText: 'Enter your password',
// Here is key idea
suffixIcon: IconButton(
icon: Icon(
// Based on passwordVisible state choose the icon
_passwordVisible
? Icons.visibility
: Icons.visibility_off,
color: Theme.of(context).primaryColorDark,
),
onPressed: () {
// Update the state i.e. toogle the state of passwordVisible variable
setState(() {
_passwordVisible = !_passwordVisible;
});
},
),
),
);
First make you widget StatefulWidget
if it is a StatelessWidget
.
Then have a variable bool _obscureText
and pass it to your TextFormField
. The toggle it with setState
as required.
Example:
class _FormFieldSampleState extends State<FormFieldSample> {
// Initially password is obscure
bool _obscureText = true;
String _password;
// Toggles the password show status
void _toggle() {
setState(() {
_obscureText = !_obscureText;
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Sample"),
),
body: new Container(
child: new Column(
children: <Widget>[
new TextFormField(
decoration: const InputDecoration(
labelText: 'Password',
icon: const Padding(
padding: const EdgeInsets.only(top: 15.0),
child: const Icon(Icons.lock))),
validator: (val) => val.length < 6 ? 'Password too short.' : null,
onSaved: (val) => _password = val,
obscureText: _obscureText,
),
new FlatButton(
onPressed: _toggle,
child: new Text(_obscureText ? "Show" : "Hide"))
],
),
),
);
}
}
Hope this helps!
With a credit goes to X-Wei, you can create the widget as a separate password.dart
:
import 'package:flutter/material.dart';
class PasswordField extends StatefulWidget {
const PasswordField({
this.fieldKey,
this.hintText,
this.labelText,
this.helperText,
this.onSaved,
this.validator,
this.onFieldSubmitted,
});
final Key fieldKey;
final String hintText;
final String labelText;
final String helperText;
final FormFieldSetter<String> onSaved;
final FormFieldValidator<String> validator;
final ValueChanged<String> onFieldSubmitted;
@override
_PasswordFieldState createState() => new _PasswordFieldState();
}
class _PasswordFieldState extends State<PasswordField> {
bool _obscureText = true;
@override
Widget build(BuildContext context) {
return new TextFormField(
key: widget.fieldKey,
obscureText: _obscureText,
maxLength: 8,
onSaved: widget.onSaved,
validator: widget.validator,
onFieldSubmitted: widget.onFieldSubmitted,
decoration: new InputDecoration(
border: const UnderlineInputBorder(),
filled: true,
hintText: widget.hintText,
labelText: widget.labelText,
helperText: widget.helperText,
suffixIcon: new GestureDetector(
onTap: () {
setState(() {
_obscureText = !_obscureText;
});
},
child:
new Icon(_obscureText ? Icons.visibility : Icons.visibility_off),
),
),
);
}
}
Call it as:
import 'package:my_app/password.dart';
String _password;
final _passwordFieldKey = GlobalKey<FormFieldState<String>>();
PasswordField(
fieldKey: _passwordFieldKey,
helperText: 'No more than 8 characters.',
labelText: 'Password *',
onFieldSubmitted: (String value) {
setState(() {
this._password = value;
});
},
),
Well I personally like to keep the passwords hidden all the time and seen when you want to see them, so this is the approach I use to hide/unhide passwords,Incase you want the password to be visible when the touch is In contact with the hide icon, and hidden as soon as you remove the contact then this is for you
//make it invisible globally
bool invisible = true;
//wrap your toggle icon in Gesture Detector
GestureDetector(
onTapDown: inContact,//call this method when incontact
onTapUp: outContact,//call this method when contact with screen is removed
child: Icon(
Icons.remove_red_eye,
color: colorButton,
),
),
void inContact(TapDownDetails details) {
setState(() {
invisible = false;
});
}
void outContact(TapUpDetails details) {
setState(() {
invisible=true;
});
}
This approach is being used in of my packages https://pub.dev/packages/passwordfield
The output of the above code
I did it with holding and releasing the longTap:
bool _passwordVisible;
@override
void initState() {
_passwordVisible = false;
super.initState();
}
// ...
TextFormField(
obscureText: !_passwordVisible,
decoration: InputDecoration(
hasFloatingPlaceholder: true,
filled: true,
fillColor: Colors.white.withOpacity(0.5),
labelText: "Password",
suffixIcon: GestureDetector(
onLongPress: () {
setState(() {
_passwordVisible = true;
});
},
onLongPressUp: () {
setState(() {
_passwordVisible = false;
});
},
child: Icon(
_passwordVisible ? Icons.visibility : Icons.visibility_off),
),
),
validator: (String value) {
if (value.isEmpty) {
return "*Password needed";
}
},
onSaved: (String value) {
_setPassword(value);
},
);