TextField hides behind Keyboard in Flutter 3.0.0
Asked Answered
S

3

9

I cannot get CustomScrollView to work properly.

Before flutter 2.13.0-0.2.pre, tapping on a TextFields inside a CustomScrollView automatically adjusts the TextField above the keyboard as it opens.

On downgrading my flutter version to 2.11.0-0.1.pre and running the application on Android version 11, scrollview works as expected - even without tweaking the Scaffold widget by adding resizeToAvoidBottomInset: false - when a user taps a TextField, the keyboard comes out and the user can scroll to the bottom as it should be.

However after upgrading to Flutter 3.0.0, things changed. When i tap a TextField and the keyboard comes out, i cannot scroll to the bottom of the screen. Actually, scrolling doesn't work at all.

Here's an example of a very long Form with about 26 TextFields. Tapping the 25th TextField opens the keyboard which covers that 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'),
                ),
              ]),
            ),
          ),
        ),
      ],
    ),
  );
}

I googled this behavior and found some answers,

  • Adding resizeToAvoidBottomInset: false to the Scaffold widget
  • Wrapping the CustomScrollView widget with a SingleChlidScrollView and setting the reverse property to true.
  • Adding <item name="android:windowFullscreen">true</item> to styles.xml
  • Setting scrollPadding: EdgeInsets.only(bottom:40) on the TextField [A property on the TextField Widget]
  • Listening to WidgetsBinding.instance?.window.onMetricsChanged & using setState((){}) to update the bottom padding of the TextField whenever the keyboard pops out

And so many others just to list a few.

I tried all the above solutions, but they either don't fix the issue or just feels like a lot of work compared to the normal way scrollviews should work. On checking the Flutter 3.0.0 changelog, i couldn't find any reference to this change in scrollview.

Am I missing something? Was there a change to CustomScrollView in flutter 3.0.0? Any idea how i can resolve this issue?

Here is the result of 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!

EDIT: This issue affects Android and iOS.

Suetonius answered 23/5, 2022 at 21:9 Comment(0)
S
12

I found the solution. I had installed the flutter_screenutil package and inserted it above my widget tree - above MaterialApp and I'd also set useInheritedMediaQuery: true. This prevented widget rebuilds for things like keyboard state change.

Moving the ScreenUtils widget below MaterialApp fixed it.

Suetonius answered 24/5, 2022 at 19:23 Comment(3)
Hey im facing the same problem and tried all the solution you mentioned before, also this one but it doesnt work, i keep the resizeToAvoidBottomInset as true but the keyboard keeps hiding the textfield. Im using a SingleChildScrollView btwRooseveltroost
In my case, I was able to find the bug by creating a new Flutter project, then I had to gradually copy and paste from the previous project to the new one. Very tedious, but guaranteed to work.Suetonius
Thanks a lot man, I was using flutter_screenutil too, but for me setting useInheritedMediaQuery to false did the trickTelugu
K
2

You can just try -

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

Place it directly under the first return of build of the screen. Hope it helps....

Kumasi answered 24/5, 2022 at 6:10 Comment(2)
Actually i don't want to use SingleChildScrollView. This should still be achievable using CustomScrollView with Slivers, but doesn't work.Suetonius
This works for me when I use SingleChildScrollView also I have resizeToAvoidBottomInset set to true.Jostle
P
2

Many answers are stating to use different keys and widgets for this purpose, but in my case ScreenUtil package worked. Wrap your main app widget like MaterialApp into screenutil and make useInheritedMediaQuery: true. It will work.

Pertinacious answered 10/6, 2023 at 9:34 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.