如何在 TextFormField 中显示/隐藏密码?
Posted
技术标签:
【中文标题】如何在 TextFormField 中显示/隐藏密码?【英文标题】:How to show/hide password in TextFormField? 【发布时间】:2018-08-13 23:17:14 【问题描述】:目前我的密码TextFormField
是这样的:
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,
);
我想要一个像交互这样的按钮,它可以使密码可见和不可见。我可以在TextFormField
里面做吗?或者我将不得不制作一个Stack
小部件来获得我所需的用户界面。以及obscureText
真/假的条件如何?
【问题讨论】:
只需将传递给obscureText
的true
设为变量并切换它,例如在传递给`onPressed: if a button 的函数中
【参考方案1】:
我按照@Hemanth Raj 创建了一个解决方案,但采用了更强大的方式。
首先声明一个bool
变量_passwordVisible
。
在initState()
中启动_passwordVisible
到false
@override
void initState()
_passwordVisible = false;
下面是TextFormField
小部件:
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;
);
,
),
),
);
【讨论】:
在默认的 Normal 情况下,页面加载密码被隐藏,因此将 passwordVisible 初始化为 true 即passwordVisible= true
,并且在这种情况下使其有意义将变量 passwordVisible
替换为 passwordObscured= true
除了 nelson 指出的内容之外,一个简单的解决方法是 obscureText: !passwordVisible
感谢这对我有用..!但验证器不工作
太棒了!像我想要的那样完美地工作【参考方案2】:
如果它是StatelessWidget
,首先让你的小部件StatefulWidget
。
然后有一个变量bool _obscureText
并将其传递给您的TextFormField
。根据需要使用setState
切换它。
例子:
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"))
],
),
),
);
希望这会有所帮助!
【讨论】:
感谢您的帮助。我使用堆栈而不是容器。所以密码与按钮重叠。我将填充放在 FlatButton 容器中。还是重叠的。知道如何解决吗? 但是为什么要堆叠呢?水平排列试试Row
,垂直排列试试Column
设计如下:i.stack.imgur.com/q8aQU.png 不是图标,而是平面按钮。因为它是我使用 Stack 的 TextFormField 的顶部。
不需要 Stack。 InputDecoration
有一个 suffixIcon
属性,这可能正是您正在寻找的。span>
Cupertino 似乎仍需要 Stack? suffixIcon 似乎只适用于 Material。【参考方案3】:
感谢X-Wei,您可以将小部件创建为单独的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),
),
),
);
称它为:
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;
);
,
),
【讨论】:
【参考方案4】:嗯,我个人喜欢一直隐藏密码,并在您想看到它们时看到,所以这是我用来隐藏/取消隐藏密码的方法,以防您希望密码在触摸时可见带有隐藏图标的联系人,并在您删除联系人后立即隐藏,那么这是给您的
//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;
);
我的包中使用了这种方法 https://pub.dev/packages/passwordfield
以上代码的输出
【讨论】:
【参考方案5】:我通过按住并释放 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);
,
);
【讨论】:
【参考方案6】:此解决方案可防止点击 suffixIcon 将焦点赋予 TextField,但如果 TextField 已获得焦点并且用户想要显示/隐藏密码,则焦点不会丢失。
import 'package:flutter/material.dart';
class PasswordField extends StatefulWidget
const PasswordField(Key? key) : super(key: key);
@override
_PasswordFieldState createState() => _PasswordFieldState();
class _PasswordFieldState extends State<PasswordField>
final textFieldFocusNode = FocusNode();
bool _obscured = false;
void _toggleObscured()
setState(()
_obscured = !_obscured;
if (textFieldFocusNode.hasPrimaryFocus) return; // If focus is on text field, dont unfocus
textFieldFocusNode.canRequestFocus = false; // Prevents focus if tap on eye
);
@override
Widget build(BuildContext context)
return TextField(
keyboardType: TextInputType.visiblePassword,
obscureText: _obscured,
focusNode: textFieldFocusNode,
decoration: InputDecoration(
floatingLabelBehavior: FloatingLabelBehavior.never, //Hides label on focus or if filled
labelText: "Password",
filled: true, // Needed for adding a fill color
fillColor: Colors.grey.shade800,
isDense: true, // Reduces height a bit
border: OutlineInputBorder(
borderSide: BorderSide.none, // No border
borderRadius: BorderRadius.circular(12), // Apply corner radius
),
prefixIcon: Icon(Icons.lock_rounded, size: 24),
suffixIcon: Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 4, 0),
child: GestureDetector(
onTap: _toggleObscured,
child: Icon(
_obscured
? Icons.visibility_rounded
: Icons.visibility_off_rounded,
size: 24,
),
),
),
),
);
【讨论】:
【参考方案7】:class SignIn extends StatefulWidget
@override
_SignInState createState() => _SignInState();
class _SignInState extends State<SignIn>
// Initially password is obscure
bool _obscureText = true;
// Toggles the password show status
void _togglePasswordStatus()
setState(()
_obscureText = !_obscureText;
);
@override
Widget build(BuildContext context)
return
Scaffold(
backgroundColor: Colors.brown[100],
appBar: AppBar(
backgroundColor: Colors.brown[400],
elevation: 0.0,
title: Text('Sign In'),
),
body: Container(
padding: EdgeInsets.symmetric(vertical:20.0,horizontal:50.0),
child: Form(
key: _formKey,
child: Column(children: <Widget>[
TextFormField(
decoration: InputDecoration(
hintText: 'Password',
suffixIcon: IconButton(
icon:Icon(_obscureText ? Icons.visibility:Icons.visibility_off,),
onPressed: _togglePasswordStatus,
color: Colors.pink[400],
),
),
validator: (val)
return
val.length < 6 ? 'Enter A Password Longer Than 6 Charchters' :null;
,
obscureText: _obscureText,
onChanged: (val)
setState(()
password = val.trim();
);
,
),
],),),
),
);
【讨论】:
这个答案可以使用更多的上下文。解释它的作用以及它如何改进以前的答案。【参考方案8】:这是一个带有内置材料设计图标的更简单示例:
child: TextFormField(
decoration: InputDecoration(
fillColor: Color(0xFFFFFFFF), filled: true,
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xFF808080)),
),
suffixIcon: GestureDetector(
onTap: ()
setState(()
_showPassword = !_showPassword;
);
,
child: Icon(
_showPassword ? Icons.visibility : Icons.visibility_off,
),
),
labelText: 'Password'),
obscureText: !_showPassword,
),
【讨论】:
【参考方案9】: bool _obscuredText = true;
_toggle()
setState(()
_obscuredText = !_obscuredText;
);
Widget _createPassword()
return TextField(
obscureText: _obscuredText,
cursorColor: Colors.black54,
style: TextStyle( color: Colors.black54),
decoration: InputDecoration(
labelStyle: TextStyle(
color: Colors.black54
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.black54
)
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0)
),
labelText: 'Contraseña',
hintText: 'Contraseña',
suffixIcon: FlatButton(onPressed: _toggle, child:Icon(Icons.remove_red_eye, color: _obscuredText ? Colors.black12 : Colors.black54))
),
onChanged: (value)
setState(()
_password = value;
);
,
);
希望这会有所帮助!
【讨论】:
【参考方案10】:○ 只需简单的 3 个步骤,您就可以完成密码显示/隐藏。
第一步:创建变量
bool _isHidden = true;
第2步:神奇的步骤,使图标可点击并查看/隐藏密码。
现在我将用 InkWell 包裹图标,使其可点击。所以,当我们点击它时,它会在 obscureText 参数的真假之间切换。
@override
Widget build(BuildContext context)
return Scaffold(
backgroundColor: Theme.of(context).secondaryHeaderColor,
body: Center(
child: Container(
height: 55,
alignment: Alignment.center,
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
child: TextField(
obscureText: _isHidden,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Password',
suffix: InkWell(
onTap: _togglePasswordView, /// This is Magical Function
child: Icon(
_isHidden ? /// CHeck Show & Hide.
Icons.visibility :
Icons.visibility_off,
),
),
/*icon: Icon(
Icons.password_sharp,
color: Colors.black,
),*/
),
),
),
),
);
第 3 步:创建这个神奇的功能。
void _togglePasswordView()
setState(()
_isHidden = !_isHidden;
);
☻♥完成。
【讨论】:
【参考方案11】:感谢@Parikshit Chalke 的回答。然而,
如果您只想更新您的TextFormField
和IconButton
,setState
的通话费用非常昂贵。相反,将其包装在 StatefulBuilder 中,并且只更新子项。
示例解决方案:
import 'package:flutter/material.dart';
class MyWidget extends StatefulWidget
@override
_MyWidgetState createState() => _MyWidgetState();
class _MyWidgetState extends State<MyWidget>
// initially password is invisible
bool _passwordVisible = false;
String _password;
@override
Widget build(BuildContext context)
return Column(
children: [
// other widget that does not need update when password visibility is toggled
Text("I do not require update"),
StatefulBuilder(builder: (_context, _setState)
// only following widget gets update when _setState is used
return TextFormField(
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(
_passwordVisible ? Icons.visibility : Icons.visibility_off,
),
onPressed: ()
// use _setState that belong to StatefulBuilder
_setState(()
_passwordVisible = !_passwordVisible;
);
,
),
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,
);
),
],
);
【讨论】:
【参考方案12】:我有更有用的解决方案。您可以使用 Provider 并使用 Consumer Widget 监听 TextFormField
obscure_text_state.dart
import 'package:flutter/material.dart';
class ObscureTextState with ChangeNotifier
bool _isTrue = true;
bool get isTrue => _isTrue;
get switchObsIcon
return _isTrue ? Icon(Icons.visibility_off) : Icon(Icons.visibility);
void toggleObs()
_isTrue = !_isTrue;
notifyListeners();
那么你应该用 TextFromField 所在的 Consumer 监听那个状态。
Consumer<ObscureTextState>(
builder: (context, obs, child)
return TextFormField(
controller: _passwordController,
validator: (value)
if (value.isEmpty)
return "Alan boş bırakılamaz!";
else if (value.length < 6)
return "Şifre en az 6 haneden oluşmalıdır.";
else
return null;
,
obscureText:
Provider.of<ObscureTextState>(context, listen: false)
.isTrue,
decoration: InputDecoration(
prefixIcon: Icon(Icons.lock),
suffixIcon: IconButton(
onPressed: ()
Provider.of<ObscureTextState>(context, listen: false)
.toggleObs();
,
icon: Provider.of<ObscureTextState>(context,
listen: false)
.switchObsIcon,
),
hintText: "Şifre",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0))),
);
,
),
【讨论】:
【参考方案13】: TextFormFeild(
decoration:InputDecoration(
icon: _isSecurityIcon == true
? IconButton(
icon: Icon(Icons.visibility_off_outlined),
onPressed: ()
setState(()
_isSecurityIcon = false;
);
,
)
: IconButton(
icon: Icon(Icons.visibility_outlined),
onPressed: ()
setState(
()
_isSecurityIcon = true;
,
);
,
),
),
);```
【讨论】:
以上是关于如何在 TextFormField 中显示/隐藏密码?的主要内容,如果未能解决你的问题,请参考以下文章
在 Web 上,如何控制自动显示在焦点 TextFormField 上的可见性图标,该 TextFormField 的 obscureText 属性设置为 true?
[译]TextField/TextFormField 如何显示/隐藏密码