Flutter 3.0.0中的TextField被键盘遮挡问题

9

我无法正确使用CustomScrollView

在flutter 2.13.0-0.2.pre之前,点击CustomScrollView中的TextFields会自动调整上方的TextField,以适应键盘的打开。

将flutter版本降级到2.11.0-0.1.pre并在Android 11上运行应用程序时,即使没有通过添加resizeToAvoidBottomInset: false来调整小部件,scrollview也能正常工作-当用户点击一个TextField时,键盘弹出,用户可以像应该一样向下滚动到底部。

但是在升级到Flutter 3.0.0后,情况发生了变化。当我点击TextField并弹出键盘时,我不能滚动到屏幕底部。实际上,滚动根本无法工作。

以下是一个非常长的表单示例,包含大约26个TextFields。 点击第25个TextField会打开键盘,覆盖该TextField。

@override
Widget build(BuildContext context) {
  return Scaffold(
    backgroundColor: const Color(0xff185C66),
    resizeToAvoidBottomInset: true,
    body: CustomScrollView(
      shrinkWrap: true,
      clipBehavior: Clip.antiAlias,
      controller: ScrollController(),
      scrollDirection: Axis.vertical,
      slivers: [
        SliverPadding(
          padding: EdgeInsets.symmetric(horizontal: App.sidePadding),
          sliver: SliverList(
            delegate: SliverChildListDelegate.fixed([
              SafeArea(
                bottom: false,
                child: AdaptiveText(
                  'Welcome Back',
                  maxLines: 1,
                  fontSize: 24.sp,
                  maxFontSize: 25,
                  fontWeight: FontWeight.w600,
                  textColor: Colors.white,
                  textColorDark: Colors.white,
                ),
              ),
              //
              0.02.verticalh,
              //
              SizedBox(
                width: 0.71.w,
                child: AdaptiveText(
                  'Login with your email and password to continue to your account',
                  fontSize: 16.sp,
                  maxFontSize: 17,
                  textColor: Colors.white,
                  textColorDark: Colors.white,
                ),
              ),
              //
              0.045.verticalh,
              //
              TextFormField(keyboardType: TextInputType.name),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.visiblePassword),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.emailAddress),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.emailAddress),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.streetAddress),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.emailAddress),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.datetime),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.datetime),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.datetime),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.datetime),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.emailAddress),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.phone),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.emailAddress),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.phone),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.phone),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.phone),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.phone),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.emailAddress),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.emailAddress),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.emailAddress),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.text),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.text),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.text),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.text),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.text),
              const SizedBox(height: 12),
              TextFormField(keyboardType: TextInputType.text),
              const SizedBox(height: 12),
            ]),
          ),
        ),
        //
        SliverPadding(
          padding: EdgeInsets.symmetric(horizontal: App.sidePadding),
          sliver: SliverSafeArea(
            top: false,
            sliver: SliverList(
              delegate: SliverChildListDelegate.fixed([
                SizedBox(height: 16),
                //
                TextButton(
                  onPressed: () {},
                  child: Text('Login'),
                ),
              ]),
            ),
          ),
        ),
      ],
    ),
  );
}

我谷歌了这个行为并找到了一些答案,
  • 向Scaffold小部件添加resizeToAvoidBottomInset: false
  • 使用SingleChlidScrollView包装CustomScrollView小部件,并将reverse属性设置为true
  • 在styles.xml中添加<item name="android:windowFullscreen">true</item>
  • 在TextField上设置scrollPadding: EdgeInsets.only(bottom:40)[一个TextField Widget上的属性]
  • 侦听WidgetsBinding.instance?.window.onMetricsChanged并使用setState((){})在键盘弹出时更新TextField的底部填充

还有许多其他解决方案仅列举几个。

我尝试了上述所有解决方案,但它们要么无法解决问题,要么与正常滚动视图工作方式相比,感觉就像很多工作。 在检查Flutter 3.0.0更改日志时,我找不到任何关于此更改的滚动视图的参考。

我错过了什么吗? 在flutter 3.0.0中是否对CustomScrollView进行了更改? 有什么方法可以解决这个问题吗?

这里是flutter doctor -v的结果。

[✓] Flutter (Channel stable, 3.0.0, on macOS 12.3.1 21E258 darwin-x64, locale en-NG)
    • Flutter version 3.0.0 at /Users/brendan/src/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision ee4e09cce0 (2 weeks ago), 2022-05-09 16:45:18 -0700
    • Engine revision d1b9a6938a
    • Dart version 2.17.0
    • DevTools version 2.12.2

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0-rc2)
    • Android SDK at /Users/brendan/Library/android/sdk
    • Platform android-31, build-tools 33.0.0-rc2
    • ANDROID_HOME = /Users/brendan/Library/android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7590822)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
       https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
       https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7590822)

[✓] VS Code (version 1.67.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.40.0

[✓] Connected device (3 available)
    • Redmi Note 9S (mobile) • 702f6413 • android-arm64  • Android 11 (API 30)
    • macOS (desktop)        • macos    • darwin-x64     • macOS 12.3.1 21E258 darwin-x64
    • Chrome (web)           • chrome   • web-javascript • Google Chrome 101.0.4951.64
    ! Error: j@mon is not connected. Xcode will continue when j@mon is connected. (code -13)

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!

编辑:此问题影响Android和iOS。

3个回答

12

我找到了解决方案。我安装了flutter_screenutil包,并将其插入到我的小部件树中 - 在MaterialApp之上,我还设置了useInheritedMediaQuery: true。这阻止了像键盘状态更改之类的小部件重建。

ScreenUtils小部件移动到MaterialApp之下即可解决问题。


嘿,我遇到了同样的问题,并尝试了你之前提到的所有解决方案,包括这个,但它不起作用。我将resizeToAvoidBottomInset保持为true,但键盘仍然会隐藏textfield。顺便说一下,我正在使用SingleChildScrollView。 - Jocgomez
1
在我的情况下,我能够通过创建一个新的Flutter项目来找到错误,然后我必须逐步从以前的项目中复制和粘贴到新项目中。非常繁琐,但保证有效。 - Brendan
1
非常感谢,我也在使用flutter_screenutil,但是对我来说将useInheritedMediaQuery设置为false就解决了问题。 - KIRAx2000

2

你可以试试 -

@override
Widget build(BuildContext context) {
  return Scaffold( 
    body: SingleChildScrollView(
            physics: AlwaysScrollablePhysics(),
            child: 
          ),
    ),

将其直接放置在屏幕构建的第一个返回下方。希望能有所帮助...


实际上,我不想使用SingleChildScrollView。这应该仍然可以通过使用具有Slivers的CustomScrollView来实现,但并不起作用。 - Brendan
这对我有用,当我使用SingleChildScrollView时,同时我也将resizeToAvoidBottomInset设置为true。 - J.Maher

1
很多答案都提到使用不同的键和小部件来实现这个目的,但在我的情况下,ScreenUtil包起作用。 将你的主应用小部件像MaterialApp一样包裹在screenutil中,并设置useInheritedMediaQuery: true。它会起作用。

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