【问题标题】:How to show/hide password in TextFormField?如何在 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真/假的条件如何?

【问题讨论】:

  • 只需将传递给obscureTexttrue 设为变量并切换它,例如在传递给`onPressed: if a button 的函数中

标签: android dart flutter


【解决方案1】:

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

【讨论】:

  • 在默认的 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 的回答。然而, 如果您只想更新您的TextFormFieldIconButtonsetState 的通话费用非常昂贵。相反,将其包装在 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;
                        },
                        );
                        },
                       ),
                       ),
                      );```
                    

                    【讨论】:

                      猜你喜欢
                      • 2021-08-25
                      • 2011-06-10
                      • 2021-02-26
                      • 1970-01-01
                      • 1970-01-01
                      • 2021-12-01
                      • 2018-01-15
                      • 1970-01-01
                      • 2015-09-26
                      相关资源
                      最近更新 更多