如何将带有文本字段(自动聚焦为真)的底部表单移动到键盘的位置?

246

我正在尝试制作一个底部表,其中有一个文本字段,并将自动对焦设置为真,以便弹出键盘。但是,底部表被键盘覆盖了。是否有一种方法可以将底部表移到键盘上方?

Padding(
  padding:
      EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
  child: Column(children: <Widget>[
    TextField(
      autofocus: true,
      decoration: InputDecoration(hintText: 'Title'),
    ),
    TextField(
      decoration: InputDecoration(hintText: 'Details!'),
      keyboardType: TextInputType.multiline,
      maxLines: 4,
    ),
    TextField(
      decoration: InputDecoration(hintText: 'Additional details!'),
      keyboardType: TextInputType.multiline,
      maxLines: 4,
    ),]);

1
Github上还有一些未解决的问题:主要问题另一个问题,其中有一条评论提供了一个动画解决方案。 - Sven
7
对我来说,只需要在Column的最后添加一个Padding元素,并将其填充设置为padding: MediaQuery.of(context).viewInsets即可。 - Huy
1
@Huy 谢谢。你应该把你的评论放到答案里。 - Abdul Qadir
28个回答

385
  • 解决此问题的方法:
  1. 您只需使用 MediaQuery.of(context).viewInsets.bottom 来添加键盘内边距即可。

  2. 为了更好的效果,将 isScrollControlled = true 设置为 BottomSheetDialog,这将允许底部工作表占用完整所需高度。

  • 请注意,如果您的 BottomSheetModelColumn,请确保添加 mainAxisSize: MainAxisSize.min,否则工作表将覆盖整个屏幕。

  • 示例:

showModalBottomSheet(
        context: context,
        isScrollControlled: true,
        builder: (context) => Padding(
          padding: EdgeInsets.only(
                        bottom: MediaQuery.of(context).viewInsets.bottom),
          child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 12.0),
                    child: Text('Enter your address',
                        style: TextStyles.textBody2),
                  ),
                  SizedBox(
                    height: 8.0,
                  ),
                  TextField(
                      decoration: InputDecoration(
                        hintText: 'adddrss'
                      ),
                      autofocus: true,
                    ),                 
                ],
              ),
        ));
  • 已更新

Flutter 2.2又一次改变了!现在你需要再次给予底部填充,以防止键盘覆盖底部表单。


3
应用后,底部工作表占据了整个屏幕。通过为底部工作表的 Container widget 的高度属性设置静态值来解决这个问题。 - dkea
3
@Abed,我尝试了您的方法。它对我的问题没有起作用。请查看 https://dev59.com/mbbna4cB1Zd3GeqPfrhP。 - BIS Tech
5
2021年!现在不需要它:padding: MediaQuery.of(context).viewInsets。注:该代码段是Flutter中的Dart代码,用于设置UI元素的内边距。 - Akbar Pulatov
1
在 showModalBottomSheet 中添加 "isScrollControlled = true",并在 Column 组件中添加 "mainAxisSize: MainAxisSize.min" 解决了我所有的问题。谢谢 Abed。 - Kamlesh
2
如何在可滚动的模态框中,当输入框获得焦点时添加自动滚动? - Darkhan
显示剩余8条评论

197

只需添加以下内容:

  • isScrollControlled: true添加到showModalBottomSheet中
  • padding: MediaQuery.of(context).viewInsets添加到builder组件中
  • column和wrap都可以使用
showModalBottomSheet<void>(
  isScrollControlled: true,
  context: context,
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.only(
        topLeft: Radius.circular(30.0),
        topRight: Radius.circular(30.0)),
  ),
  builder: (BuildContext context) {
    return Padding(
        padding: MediaQuery.of(context).viewInsets,
        child: Container(
            child: Wrap(
          children: <Widget>[
            TextField(
              decoration: InputDecoration(
                  border: InputBorder.none,
                  hintText: 'Enter a search term'),
            ),
            TextField(
              decoration: InputDecoration(
                  border: InputBorder.none,
                  hintText: 'Enter a search term'),
            ),
            TextField(
              decoration: InputDecoration(
                  border: InputBorder.none,
                  hintText: 'Enter a search term'),
            ),
            TextField(
              decoration: InputDecoration(
                  border: InputBorder.none,
                  hintText: 'Enter a search term'),
            )
          ],
        )));
  },
);

2020年2月25日更新更好的解决方案。

showModalBottomSheet(
 isScrollControlled: true,
 builder: (BuildContext context) {

    return SingleChildScrollView(
      child: Container(
        padding:
            EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
        child: Padding(
          padding: const EdgeInsets.fromLTRB(20.0, 20.0, 20.0, 0.0), // content padding
          child: Form(...)) // From with TextField inside


});

3
提醒大家:针对所提出的问题,Wrap小部件并不是必需的,因为问题是关于bottomSheet能否在键盘上方移动,而不是bottomSheet本身的内容。请注意。 - Pedro Massango
它对我有效。 - Mofidul Islam
工作得很好,谢谢。 - Amir

42
为了在 BottomSheet 中专注于键盘 - 将 TextField 包裹在像以下示例代码中的 Padding Widget 中:
showModalBottomSheet(
              context: context,
              builder: (context) {
                return Container(
                  child: Padding(
                    padding: EdgeInsets.only(
                        bottom: MediaQuery.of(context).viewInsets.bottom),
                    child: TextField(
                      autofocus: true,
                    ),
                  ),
                );
              }); 

1
嗨,谢谢。这个方法适用于两个子字段,但是当我们添加第三个字段时就不起作用了。我已经在问题中编辑了我的代码示例。 - Manjunath Rao
@ManjunathRao 你可能需要在文本字段中添加“Key”以使它们保持唯一,以便获取超过2个。如果这有帮助,请告诉我。 - zuckerburg
BottomSheet-具有maxHeight: constraints作为字段增加高度不会增加。您可以在BottomSheet中使用ListView使字段可在滚动中可见。或者您可以尝试此方法-https://dev59.com/CFQJ5IYBdhLWcg3wsIBY - anmol.majhail
@ManjunathRao - 由于 maxHeight: constraints 的限制,底部工作表中不会有超过两个字段。 - anmol.majhail

25
在最新的Flutter版本中,您可以使用isScrollControlled属性/命名参数移动您的bottomSheet。假设我有一个函数(_showModal),当按下按钮时将调用该函数。并且我在该函数上定义了bottom sheet功能。
void _showModal() {
  showModalBottomSheet(
    isScrollControlled: true,
    context: context,
    builder: (BuildContext context) {
      return Column(
        children: <Widget>[
          TextField(// your other code),
          SizedBox(height: 5.0),
          TextField(// your other code),
          SizedBox(height: 5.0),
          TextField(// your other code),
        ]
      );
    },
  );
}

这里将出现一个ModalBottomSheet,但是它的高度为全屏,而你并不需要这个高度。因此,你需要将Column的mainAxisSize设置为min

Column(
  mainAxisSize: MainAxisSize.min,
  // your other code
)

全屏高度的问题得到了解决,但是在出现键盘时ModalBottomSheet没有移到顶部。要解决这个问题,您需要将viewInsets底部填充设置为ModalBottomSheet。因此,为了设置填充,我们需要用Container或Padding包装我们的Column,然后设置填充。最终代码如下:
void _showModal() {
  showModalBottomSheet(
    isScrollControlled: true,
    context: context,
    builder: (BuildContext context) {
      return Container(
        padding: EdgeInsets.only(
          bottom: MediaQuery.of(context).viewInsets.bottom,
        ),
        // You can wrap this Column with Padding of 8.0 for better design
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            TextField(// your other code),
            SizedBox(height: 5.0),
            TextField(// your other code),
            SizedBox(height: 5.0),
            TextField(// your other code),
          ]
        ),
      );
    },
  );
}

希望您的问题已经解决。谢谢。

2
运行得非常顺畅...! - deepak raj

22

包: https://pub.dev/packages/modal_bottom_sheet

将您的部件包装在Padding中,并像这样设置填充==>

padding: MediaQuery.of(context).viewInsets // viewInsets will decorate your screen

您可以使用 showMaterialModalBottomSheet、showModalBottomSheet 或 showCupertinoModalBottomSheet。

showModalBottomSheet(
        context: context,
        barrierColor: popupBackground,
        isScrollControlled: true, // only work on showModalBottomSheet function
        shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.only(
                topLeft: Radius.circular(borderRadiusMedium),
                topRight: Radius.circular(borderRadiusMedium))),
        builder: (context) =>  Padding(
            padding: MediaQuery.of(context).viewInsets,
            child: Container(
                   height: 400, //height or you can use Get.width-100 to set height
                   child: <Your Widget here>
             ),)),)

before

after


你好,请问你在你的应用程序中使用了哪种字体? - Vrajendra Singh Mandloi
这是Ubuntu操作系统。您可以从此处下载-> https://fonts.google.com/specimen/Ubuntu - Rasel Khan

20

尝试这个

我的解决方案是

  • 使用 isScrollControlled: true
  • 添加 Padding
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom)
  • 将您的布局包装在SingleChildScrollView
  • 示例代码

    Future<void> future = showModalBottomSheet(
      context: context,
      isDismissible: true,
      isScrollControlled: true,
      backgroundColor: Colors.white.withOpacity(0.2),
      builder: (context) => SingleChildScrollView(
        child: GestureDetector(
          child: Padding(
            padding: EdgeInsets.only(
              bottom: MediaQuery.of(context).viewInsets.bottom
            ),
            child: Container(
              width: MediaQuery.of(context).size.width,
              height: MediaQuery.of(context).size.height,
              child: Column(
                children: <Widget>[
                  // add your widget here
                ],
              ),
            ),
          )
        ),
      )
    );
    

    2
    SingleChildScrollView包装的重点很重要。谢谢。 - Nero
    这有助于保持对称性..谢谢 - Debasis Sil

    13

    当键盘弹出时,通过增加子小部件的高度来解决了问题。 初始值为MediaQuery.of(context).viewInsets.bottom将为0,当键盘获得焦点时将发生更改。

    showModalBottomSheet<void>(
          enableDrag: true,
          isScrollControlled: true,
          context: context,
          builder: (BuildContext context) {
            return Card(
              color: Colors.white,
              child: Container(
                height: MediaQuery.of(context).size.height / 2 +
                    MediaQuery.of(context).viewInsets.bottom,
                child: Column(
                  children: <Widget>[
                    TextField(),
                    TextField(),
                  ],
                ),
              ),
            );
          },
        );
    

    这就是我想要的行为!恭喜! - Cícero Moura

    12

    对于尝试了所有答案都无法解决问题的人,这些答案是正确的,但不是很清晰。

    在使用时

    MediaQuery.of(context).viewInsets.bottom)

    确保您的上下文变量正在使用底部工作表生成器属性提供的上下文变量。

    builder:(**c**)=>MediaQuery.of(**c**)


    谢谢,只需将我的showModalBottomSheet上下文更改即可解决问题。 - geniusvale
    谢谢,只需将我的showModalBottomSheet上下文更改即可解决问题。 - undefined

    11

    2021年5月更新Flutter 2.2! 现在您需要提供下部填充。下面的文字是一个bug。

    2020年更新!

    这个答案是正确的,但是现在您不必再提供底部填充! 找到并删除此行:

    padding: MediaQuery.of(context).viewInsets


    2
    谢谢,提示很好。你的解决方案对我有用(Flutter稳定版本60bd88df91)。但是请查看ref a5262(还原“[showModalBottomSheet] fix:showModalBottomSheet不会沿着键盘移动”)在https://github.com/flutter/flutter/commits/master/packages/flutter/lib/src/material/bottom_sheet.dart。所以我想我们可能需要跟踪Flutter即将推出的更新中的问题。 - navid
    1
    确认了,Flutter 2.2 又出问题了,你需要再次使用 MediaQuery。 - Jeff L.

    7
    在底部工作表的最后一个小部件之后添加此内容。
    Padding(padding: EdgeInsets.only(bottom:MediaQuery.of(context).viewInsets.bottom))
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接