如何在 TextFormField 中显示/隐藏密码?

目前我的密码 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小部件来获得我所需要的 UI。那么关于 obscureText的真/假条件是如何确定的呢?

189698 次浏览

首先让你的小部件 StatefulWidget,如果它是一个 StatelessWidget

然后有一个变量 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"))
],
),
),
);
}
}

希望这个能帮上忙!

我已经根据@Hemanth Raj 创建了一个解决方案,但是以一种更加健壮的方式。

首先声明一个 bool变量 _passwordVisible

initState()中启动 _passwordVisiblefalse

@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;
});
},
),
),
);

有了 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;
});
},
),

我握住并放开了长龙拍:

    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);
},
);

我个人喜欢一直把密码隐藏起来,当你想看到它们的时候就可以看到它们,所以这是我用来隐藏/取消隐藏密码的方法,如果你想让密码在触摸到隐藏图标的时候显示出来,那么一旦你删除了联系人就可以把它隐藏起来,那么这个就是为你准备的

//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

以上代码的输出

enter image description here

  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;
});
},
);
}

希望这个能帮上忙!

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();
});
},
),
],),),
),
);
}
}

谢谢@Parikshit Chalke 的回答, 如果你只想更新你的 TextFormFieldIconButton,那么 setState是一个非常昂贵的电话。相反,将它封装在 建设者中,并且只更新子项。

示例解决方案:

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,
);
}),
],
);
}
}


    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

省道

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();
}
}


然后,您应该使用 Consumer 监听 TextFromField 所在的状态。

            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))),
);
},
),

这里有一个内置材质设计图标的简单例子:

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,
),

这个解决方案可以防止在后缀 Icon 中的点击将焦点赋予 TextField,但是如果 TextField 被聚焦,并且用户想要显示/隐藏密码,那么焦点就不会丢失。

Result

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,
),
),
),
),
);
}
}

○只是一个简单的3个步骤,你可以遵循和密码显示/隐藏完成。


enter image description here

步骤1: 创建变量

       bool _isHidden = true;

第二步: 魔术步骤,使图标可点击,并查看/隐藏密码。

现在我将用 InkWell 包装这个图标,这样它就可以被点击了。因此,当我们点击这个参数时,它会切换到遮蔽文本的 true 和 false 之间的参数。

 @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,
),*/
),
),
),
),
);
}

第三步: 创建这个神奇的功能。

      void _togglePasswordView() {
setState(() {
_isHidden = !_isHidden;
});
}
  

完成。

//Password
const TextField(
obscureText: true, //for hide Password
decoration: InputDecoration(
prefixIcon: Icon(Icons.lock_outline),
hintText: 'Password'),
),