当焦点在 TextField 上并且在 Flutter 中打开键盘时,如何向上推送内容?

Posted

技术标签:

【中文标题】当焦点在 TextField 上并且在 Flutter 中打开键盘时,如何向上推送内容?【英文标题】:How to push content up when focus is on TextField and keyboard opens in Flutter? 【发布时间】:2022-01-18 16:38:08 【问题描述】:

当焦点位于“描述”文本字段并且键盘打开时,我需要将我的内容向上推送

without keyboard

Actual result

Expected result

       ListView(
        children: [
          Column(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text('Title'),
                  TitleField(
                    controller: titleEditingController,
                  ),
                  Text(
                    'Description',
                  ),
                  DescriptionField(
                      focusNode: _focusNode,
                      controller: descriptionEditingController),
                  DCDatePicker(),
                ],
              ),
              AddButton(),
            ],
          ),
        ],
      );

【问题讨论】:

【参考方案1】:

请参考以下代码

使用 ScrollController 可以在 Description TextField 为 onTapped 和 onFocus 时滚动到底部,方法是添加这段代码

 _controller.animateTo(
                    _controller.position.maxScrollExtent,
                    duration: Duration(seconds: 1),
                    curve: Curves.fastOutSlowIn,
                  );


final _controller = ScrollController();

ListView(
          controller: _controller,
          children: [
               Column(
                children: [
                  Text('Title'),
                  TitleField(
                    controller: titleEditingController,
                  ),
                  Text(
                    'Description',
                  ),
                  DescriptionField(
                      focusNode: _focusNode,
                      controller: descriptionEditingController),
                  DCDatePicker(),
                ],
              ),
                 
            SizedBox(
              height: 15.0,
            ),
            AddButton(),
            
            SizedBox(
              height: 250.0,
            ), // Add space at end of list view so it allows to scroll
          ],
        ),
      

请参考以下示例代码

class MainScreen extends StatefulWidget 
  MainScreen(Key key) : super(key: key);

  @override
  _MainScreenState createState() => _MainScreenState();


class _MainScreenState extends State<MainScreen> 
  final TextEditingController emailController = TextEditingController();

  final FocusNode emailFocus = FocusNode();

  final TextEditingController pswdController = TextEditingController();

  final FocusNode pswdFocus = FocusNode();

  final _validationKey = GlobalKey<FormState>();

  @override
  void initState() 
    super.initState();
  

  @override
  void dispose() 
    super.dispose();
  

  int validateEmail(String emailAddress) 
    String patttern = r'^[\w-\.]+@([\w-]+\.)+[\w-]2,4$';
    RegExp regExp = new RegExp(patttern);
    if (emailAddress.isEmpty || emailAddress.length == 0) 
      return 1;
     else if (!regExp.hasMatch(emailAddress)) 
      return 2;
     else 
      return 0;
    
  

  int validatePassword(String pswd) 
    if (pswd.isEmpty || pswd.length == 0) 
      return 1;
     else if (pswd != null && pswd.isNotEmpty && pswd.length <= 8) 
      return 2;
     else 
      return 0;
    
  

  final _controller = ScrollController();

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.lightBlue,
        automaticallyImplyLeading: true,
        leading: Icon(
          Icons.arrow_back,
        ),
        title: Text("Example"),
        centerTitle: true,
      ),
      body: Container(
        padding: EdgeInsets.all(15.0),
        child: ListView(
          controller: _controller,
          children: [
            Form(
              key: _validationKey,
              child: Column(
                children: [
                  /* Email */
                  TextFormField(
                    autovalidateMode: AutovalidateMode.onUserInteraction,
                    /* autovalidate is disabled */
                    controller: emailController,
                    keyboardType: TextInputType.emailAddress,
                    onChanged: (val) ,
                    maxLines: 1,
                    validator: (value) 
                      int res = validateEmail(value);
                      if (res == 1) 
                        return "Please  fill email address";
                       else if (res == 2) 
                        return "Please enter valid email address";
                       else 
                        return null;
                      
                    ,
                    focusNode: emailFocus,
                    autofocus: false,
                    decoration: InputDecoration(
                      errorMaxLines: 3,
                      counterText: "",
                      filled: true,
                      fillColor: Colors.white,
                      focusedBorder: OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(4)),
                        borderSide: BorderSide(
                          width: 1,
                          color: Color(0xffE5E5E5),
                        ),
                      ),
                      disabledBorder: OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(4)),
                        borderSide: BorderSide(
                          width: 1,
                          color: Color(0xffE5E5E5),
                        ),
                      ),
                      enabledBorder: OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(4)),
                        borderSide: BorderSide(
                          width: 1,
                          color: Color(0xffE5E5E5),
                        ),
                      ),
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(4)),
                        borderSide: BorderSide(
                          width: 1,
                        ),
                      ),
                      errorBorder: OutlineInputBorder(
                          borderRadius: BorderRadius.all(Radius.circular(4)),
                          borderSide: BorderSide(
                            width: 1,
                            color: Colors.red,
                          )),
                      focusedErrorBorder: OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(4)),
                        borderSide: BorderSide(
                          width: 1,
                          color: Colors.red,
                        ),
                      ),
                      hintText: "Enter email address" ?? "",
                    ),
                  ),
                  SizedBox(
                    height: 15.0,
                  ),

                  /* Password */
                  TextFormField(
                    autovalidateMode: AutovalidateMode.onUserInteraction,
                    /* autovalidate is disabled */
                    controller: pswdController,
                    inputFormatters: [
                      FilteringTextInputFormatter.deny(RegExp(r"\s\s")),
                      FilteringTextInputFormatter.deny(RegExp(
                          r'(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])')),
                    ],
                    keyboardType: TextInputType.text,
                    onChanged: (val) ,
                    maxLines: 15,
                    validator: (value) 
                      int res = validatePassword(value);
                      if (res == 1) 
                        return "Please enter password";
                       else if (res == 2) 
                        return "Please enter minimum 9 characters";
                       else 
                        return null;
                      
                    ,
                    focusNode: pswdFocus,
                    autofocus: false,
                    onTap: () 
                      _controller.animateTo(
                        _controller.position.maxScrollExtent,
                        duration: Duration(seconds: 1),
                        curve: Curves.fastOutSlowIn,
                      );
                    ,
                    decoration: InputDecoration(
                      errorMaxLines: 3,
                      counterText: "",
                      filled: true,
                      fillColor: Colors.white,
                      focusedBorder: OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(4)),
                        borderSide: BorderSide(
                          width: 1,
                          color: Color(0xffE5E5E5),
                        ),
                      ),
                      disabledBorder: OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(4)),
                        borderSide: BorderSide(
                          width: 1,
                          color: Color(0xffE5E5E5),
                        ),
                      ),
                      enabledBorder: OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(4)),
                        borderSide: BorderSide(
                          width: 1,
                          color: Color(0xffE5E5E5),
                        ),
                      ),
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(4)),
                        borderSide: BorderSide(
                          width: 1,
                        ),
                      ),
                      errorBorder: OutlineInputBorder(
                          borderRadius: BorderRadius.all(Radius.circular(4)),
                          borderSide: BorderSide(
                            width: 1,
                            color: Colors.red,
                          )),
                      focusedErrorBorder: OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(4)),
                        borderSide: BorderSide(
                          width: 1,
                          color: Colors.red,
                        ),
                      ),
                      hintText: "Enter password" ?? "",
                    ),
                  ),
                ],
              ),
            ),
            SizedBox(
              height: 15.0,
            ),
            OutlinedButton(
              onPressed: () 
                _validationKey.currentState.validate();
                if (emailController.text.isEmpty) 
                  emailFocus.requestFocus();
                 else if (pswdController.text.isEmpty ||
                    pswdController.text.length <= 8) 
                  pswdFocus.requestFocus();
                  _controller.animateTo(
                    _controller.position.maxScrollExtent,
                    duration: Duration(seconds: 1),
                    curve: Curves.fastOutSlowIn,
                  );
                
              ,
              child: Text("Validate"),
            ),
            SizedBox(
              height: 250.0,
            ),
          ],
        ),
      ),
    );
  


【讨论】:

谢谢,这个解决方案有效,但在我的情况下,当我点击文本字段两次时,它会滚动到最后。我使用 onTap,而不是 onDoubleTap 如果您在列表视图的末尾使用了尺寸大小的框,您是否添加了带有高度的尺寸框尝试降低高度并检查

以上是关于当焦点在 TextField 上并且在 Flutter 中打开键盘时,如何向上推送内容?的主要内容,如果未能解决你的问题,请参考以下文章

当应用程序启动时有两种状态时将焦点设置在 TextField 上

当initialValues通过\绑定到props.object时,如何使用Formik表单将焦点设置在TextField\input上?

当文本字段获得焦点时,如何使底部工具栏浮在软键盘上方

SwiftUI 在失去焦点时运行函数 TextField

Swing下,鼠标点击组件不是自动获得焦点的么?

强制 TextField 选择焦点上的全文