Skip to content

ModalBottomSheet with isScrollControlled doesn't respect SafeArea #39205

Description

@gabiionut

Steps to Reproduce

  1. Create a modal bottom sheet with Scaffold as its child
  2. Wrap the Scaffold into a SafeArea widget
  3. Add a Text widget in Scaffold's body
  4. Run the application on a device with notch
  5. Open the modal bottom sheet and notice that the text is under the status bar

Code example

import 'package:flutter/material.dart';

class ModalBottomSheet extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Container(),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          showModalBottomSheet(
              context: context,
              isScrollControlled: true,
              builder: (context) {
                return SafeArea(
                  child: Scaffold(
                    backgroundColor: Colors.black45,
                    body: Text(
                      'Text in safe area',
                      style: TextStyle(backgroundColor: Colors.red),
                    ),
                  ),
                );
              });
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

Screenshots

Screen Shot 2019-08-25 at 12 44 39 PM

Logs

[✓] Flutter (Channel stable, v1.7.8+hotfix.4, on Mac OS X 10.14.6 18G87, locale en-US)
    • Flutter version 1.7.8+hotfix.4 at /Users/user/flutter
    • Framework revision 20e59316b8 (5 weeks ago), 2019-07-18 20:04:33 -0700
    • Engine revision fee001c93f
    • Dart version 2.4.0

 
[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    • Android SDK at /Users/user/Library/Android/sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-28, build-tools 28.0.3
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 10.3)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 10.3, Build version 10G8
    • CocoaPods version 1.7.5

[✗] iOS tools - develop for iOS devices
    ✗ libimobiledevice and ideviceinstaller are not installed. To install with Brew, run:
        brew update
        brew install --HEAD usbmuxd
        brew link usbmuxd
        brew install --HEAD libimobiledevice
        brew install ideviceinstaller
    ✗ ios-deploy not installed. To install:
        brew install ios-deploy
    ! Brew can be used to install tools for iOS device development.
      Download brew at https://brew.sh/.

[✓] Android Studio (version 3.4)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 37.0.1
    • Dart plugin version 183.6270
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01)

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

[✓] Connected device (2 available)
    • Android SDK built for x86 • emulator-5554                        • android-x86 • Android 9 (API 28) (emulator)
    • iPhone Xs Max             • 9C9C7B29-18A5-4D3A-8F53-CE6EB58C5411 • ios         • com.apple.CoreSimulator.SimRuntime.iOS-12-4 (simulator)

! Doctor found issues in 1 category.

Activity

  1. added
    p: material_uimaterial_ui package in flutter/packages
    frameworkflutter/packages/flutter repository. See also f: labels.
    on Aug 26, 2019
  2. macoshita commented on Oct 18, 2019

    @macoshita

    In bottom_sheet.dart, use MediaQuery.removePadding(removeTop: true).

      @override
      Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
        // By definition, the bottom sheet is aligned to the bottom of the page
        // and isn't exposed to the top padding of the MediaQuery.
        Widget bottomSheet = MediaQuery.removePadding(
          context: context,
          removeTop: true,
          child: _ModalBottomSheet<T>(
            route: this,
            backgroundColor: backgroundColor,
            elevation: elevation,
            shape: shape,
            isScrollControlled: isScrollControlled
          ),
        );

    For that reason, builder's context no have paddingTop, so ModalBottomSheet doesn't respect SafeArea.

    Fix it if I change the code this:

        Widget bottomSheet = SafeArea(
          top: false,
          child: _ModalBottomSheet<T>(
            route: this,
            backgroundColor: backgroundColor,
            elevation: elevation,
            shape: shape,
            isScrollControlled: isScrollControlled,
          ),
        );

    But... I am not familiar with ModalBottomSheet's use case. I don't know if this can handle various cases.

  3. antondokusov commented on Nov 26, 2019

    @antondokusov

    Workaround:

    1. Declare InheritedWidget that holds MediaQueryData:
    class RootMediaQueryDataHolder extends InheritedWidget {
      final MediaQueryData data;
    
      RootMediaQueryDataHolder({
        Key key,
        @required this.data,
        @required Widget child,
      })  : assert(data != null),
            super(key: key, child: child);
    
      @override
      bool updateShouldNotify(InheritedWidget oldWidget) => false;
    
      static RootMediaQueryDataHolder of(BuildContext context) {
        return context.inheritFromWidgetOfExactType(RootMediaQueryDataHolder);
      }
    }
    
    1. Insert it into your MaterialApp:
        return MaterialApp(
          ...
          builder: (context, child) {
            return RootMediaQueryDataHolder(
              data: MediaQuery.of(context),
              child: child,
            );
          },
        );
    
    1. Get the data in your modal bottom sheet:
    final topPadding = RootMediaQueryDataHolder.of(context).data.padding.top;
    
  4. legalcodes commented on Dec 11, 2019

    @legalcodes
    Contributor

    Has anyone tried to replicate this issue with persistent bottom sheet? Seeing this on stable Flutter 1.91. @workerbee22

  5. layou1989 commented on Mar 15, 2020

    @layou1989

    has any solution??

  6. walidbagh commented on Apr 24, 2020

    @walidbagh

    Any news on this issue ?
    Those guys have pinpointed the source of the issue and fixed it ...
    jonataslaw/getx#44

  7. cuong1112035 commented on Apr 25, 2020

    @cuong1112035

    any update?, I have the same issue. MediaQuery.of(context).padding.top returns 0 in this case

  8. DKMonster commented on May 7, 2020

    @DKMonster

    @cuong1112035 I had same issue, and I find the reason. the context is showModalSheet context. you can try to get the main context like this code:

    Main dart file

    BuildContext mainContext = context;
    var res = await showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      builder: (BuildContext context) {
        return CalendarAddWidget(
          context: mainContext,
        );
      },
    );
    

    and using the mainContext to set MediaQuery.of(widget.context).padding.top.

    CalendarAddWidget dart file

    return Container(
      padding: EdgeInsets.only(
        top: MediaQuery.of(widget.context).padding.top,
      ),
      child: ...
    );
    

    That's solve my problem. :D

    3767

  9. TahaTesser commented on Jul 1, 2020

    @TahaTesser
    Contributor
    Code Sample
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Material App',
          theme: ThemeData.dark(),
          home: ModalBottomSheet(),
        );
      }
    }
    
    class Home extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Material App Bar'),
          ),
          body: Center(
            child: Container(
              child: Text('Hello World'),
            ),
          ),
          floatingActionButton: FloatingActionButton(
            child: Icon(Icons.add),
            onPressed: () {},
          ),
        );
      }
    }
    
    class ModalBottomSheet extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(),
          body: Container(),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              showModalBottomSheet(
                  context: context,
                  isScrollControlled: true,
                  builder: (context) {
                    return SafeArea(
                      child: Scaffold(
                        backgroundColor: Colors.black45,
                        body: Text(
                          'Text in safe area',
                          style: TextStyle(backgroundColor: Colors.red),
                        ),
                      ),
                    );
                  });
            },
            child: Icon(Icons.add),
          ),
        );
      }
    }
    
    
    flutter doctor -v
    [✓] Flutter (Channel dev, 1.20.0-2.0.pre, on Mac OS X 10.15.5 19F101, locale
        en-GB)
        • Flutter version 1.20.0-2.0.pre at /Users/tahatesser/Code/flutter_dev
        • Framework revision 15a28159bc (8 days ago), 2020-06-23 04:52:58 -0700
        • Engine revision 91a63d6a44
        • Dart version 2.9.0 (build 2.9.0-19.0.dev 7e72c9ae7e)
    
     
    [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.0)
        • Android SDK at /Users/tahatesser/Code/sdk
        • Platform android-30, build-tools 30.0.0
        • ANDROID_HOME = /Users/tahatesser/Code/sdk
        • Java binary at: /Applications/Android
          Studio.app/Contents/jre/jdk/Contents/Home/bin/java
        • Java version OpenJDK Runtime Environment (build
          1.8.0_242-release-1644-b3-6222593)
        • All Android licenses accepted.
    
    [✓] Xcode - develop for iOS and macOS (Xcode 11.5)
        • Xcode at /Applications/Xcode.app/Contents/Developer
        • Xcode 11.5, Build version 11E608c
        • CocoaPods version 1.9.3
    
    [✓] Chrome - develop for the web
        • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
    
    [✓] Android Studio (version 4.0)
        • Android Studio at /Applications/Android Studio.app/Contents
        • Flutter plugin version 47.0.2
        • Dart plugin version 193.7361
        • Java version OpenJDK Runtime Environment (build
          1.8.0_242-release-1644-b3-6222593)
    
    [✓] VS Code (version 1.46.1)
        • VS Code at /Applications/Visual Studio Code.app/Contents
        • Flutter extension version 3.12.1
    
    [✓] Connected device (4 available)
        • SM M305F      • 32003c30dc19668f • android-arm64  • Android 10 (API 29)
        • macOS desktop • macos            • darwin-x64     • Mac OS X 10.15.5
          19F101
        • Web Server    • web-server       • web-javascript • Flutter Tools
        • Chrome        • chrome           • web-javascript • Google Chrome
          83.0.4103.116
    
    • No issues found!
    
  10. added
    a: layoutSystemChrome and Framework's Layout Issues
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    on Jul 1, 2020
  11. reopened this on Nov 12, 2020
  12. 5 remaining items

  13. marianhlavac commented on Jan 30, 2021

    @marianhlavac

    Still not fixed, currently not able to create persistent bottom sheet, with correctly working SafeArea inside.

    • Scaffold.of(context).showBottomSheet(... is broken and SafeArea doesn't work in it
    • showModalBottomSheet(... works as expected and allows SafeArea to be used inside

    Is anyone looking into this?

  14. rajivrajan commented on Feb 1, 2021

    @rajivrajan

    A much simpler approach, just take the Window Object from WidgetBinding instance, and use MediaQueryData.fromWindow(WidgetsBinding.instance.window).padding.top;
    this gives you the padding required, now just place whatever widget you want in a container, with the margin :)

  15. welfvh commented on Feb 23, 2021

    @welfvh

    How is this 18 months old and still not fixed?

  16. uc-dve commented on Apr 23, 2021

    @uc-dve

    It will be fixed or not, wasting time due to searching solution but there is no solution and still using work-around.

  17. kyawthet-naing commented on May 24, 2021

    @kyawthet-naing

    That is my code->
    KyawThetNaing-solution

    showModalBottomSheet(
    backgroundColor: Colors.transparent,
    isScrollControlled: true,
    context: context,
    builder: (_) => Padding(
    padding:
    EdgeInsets.only(top: MediaQuery.of(context).padding.top),
    child: Container(color: Colors.indigo, child: Column()),
    ));

  18. steven-spiel commented on May 28, 2021

    @steven-spiel

    You may not actually need a scrollable bottom sheet if you want it to take up the whole screen.

    Depending on your use case, this might do the trick: Ineractive Example

    Naviagator.of(context).push(
      PageRouteBuilder(
        pageBuilder: (context, animation, secondaryAnimation) => Page2(),
        transitionsBuilder: (context, animation, secondaryAnimation, child) {
          var begin = Offset(0.0, 1.0);
          var end = Offset.zero;
          var curve = Curves.ease;
    
          var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
    
          return SlideTransition(
            position: animation.drive(tween),
            child: YourWidget(),
          );
        },
      )
    );
  19. N00nDay commented on Aug 26, 2021

    @N00nDay

    I can at least find work around for content in the body. I have found 0 work arounds for the appBar.

    void _createProjectToDo(BuildContext context) {
        showModalBottomSheet(
          backgroundColor: Colors.transparent,
          isScrollControlled: true,
          enableDrag: false,
          isDismissible: false,
          context: context,
          builder: (context) => SafeArea(
            child: Scaffold(
              appBar: AppBar(
                title: Text('do something right'),
              ),
            ),
          ),
        );
      }
    

    simulator_screenshot_C1C513ED-05E0-44C8-9965-0D7D78301E01

  20. self-assigned this
    on Jul 6, 2022
  21. moved this to PR submitted in Nevercodeon Jul 18, 2022
  22. added
    r: fixedIssue is closed as already fixed in a newer version
    on Jul 21, 2022
  23. Repository owner moved this from PR submitted to Done (PR merged) in Nevercodeon Jul 21, 2022
  24. github-actions commented on Aug 4, 2022

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  25. locked as resolved and limited conversation to collaborators on Aug 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

a: layoutSystemChrome and Framework's Layout Issuesfound in release: 1.20Found to occur in 1.20frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onp: material_uimaterial_ui package in flutter/packagesr: fixedIssue is closed as already fixed in a newer version

Type

No type

Projects

  • Status
    Done (PR merged)

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions