How to create a bottom sheet in Flutter

How to create a bottom sheet in Flutter

·

6 min read

In this blog, we will learn about the modal bottom sheet widget in Flutter. We will learn about the bottom sheet and where you should use them. We will also implement the Modal Bottom Sheet Widget and later we will modify it to make it scrollable.

For those of you who are trying to remember when was the last time you use to interact with the bottom sheet, The share button present in android opens up a drawer from the bottom that allows the user to select the way to share is an example of a bottom sheet.

BottomSheet Example

What is Modal Bottom Sheet?

The modal bottom sheet is a widget present in Flutter that opens an interactive drawer from the bottom of the application that allows you to display the widget. The bottom sheet will appear over other UI elements thus it prevents the user to interact with other components of apps.

When to use Modal Bottom Sheet?

The Modal Bottom Sheet is used when you want to create space for more content in your app.

It is used when you don’t want to build a separate screen for some functionality in your app that can be served without navigating the current page to another.

The modal bottom Sheet is shown in response to the user action to which it is mapped. For example, clicking on a button or icon.

The showModelBottomSheet function

To display and create a modal bottom sheet we have to use the **showModeBottomSheet **function.

These are the showModalBottomSheet function properties.

    Future<T?> showModalBottomSheet<T>({
      required BuildContext context,
      required WidgetBuilder builder,
      Color? backgroundColor,
      double? elevation,
      ShapeBorder? shape,
      Clip? clipBehavior,
      BoxConstraints? constraints,
      Color? barrierColor,
      bool isScrollControlled = false,
      bool useRootNavigator = false,
      bool isDismissible = true,
      bool enableDrag = true,
      RouteSettings? routeSettings,
      AnimationController? transitionAnimationController,
      Offset? anchorPoint,
    })

There are two required properties of showModalBottomSheet:

  1. **BuildContext: **Each widget in a tree is tracked by a locator called BuildContext, which also identifies each widget’s location inside the tree. Think of BuildContext as a location of the widget in the widget tree.

  2. WidgetBuilder: the WidgetBuilder takes in a context and returns a widget. In our case, the returned widget will be Bottom Sheet.

How to create a Bottom Sheet in Flutter

To demonstrate how to use the modal bottom sheet, I have created a project with a bottom_sheet.dart file that contains a stateful widget name CustomBottomSheet. This widget is passed into the home property of MaterialApp.

 import 'package:flutter/material.dart';

    class CustomBottomSheet extends StatefulWidget {
      const CustomBottomSheet({super.key});

      @override
      State<CustomBottomSheet> createState() => _CustomBottomSheetState();
    }

    class _CustomBottomSheetState extends State<CustomBottomSheet> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text("Geek Aid"),
            centerTitle: true,
          ),
          body: Center(
            child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
              ElevatedButton(
                  onPressed: () => showModalBottomSheet(
                      context: context, builder: (context) => buildSheet(context)),
                  child: const Text("Bottom Sheet"))
            ]),
          ),
        );
      }

      Widget buildSheet(context) {
        return Column();
      }
    }

Blank BottomSheet Flutter

The CustomBottomSheet returns a scaffold with an appBar and body. The body contains an elevated button that is centered, in onPressed an arrow function is used and the showModalBottomSheet widget is passed, and both the required property context and builder are passed.

In simple words, the button triggers the bottom sheet.

The buildSheet will draw the UI of our bottom sheet. The buildSheet widget will contain widgets that we want to display in the bottom sheet

 Widget buildSheet(context) {
      return Container(
          color: Colors.white,
          padding: const EdgeInsets.all(16),
          child: Column(children: <Widget>[
            Container(
              width: 150,
              height: 150,
              decoration: const BoxDecoration(
                shape: BoxShape.circle,
                image: DecorationImage(
                  fit: BoxFit.fill,
                  image: AssetImage('assets/logo.png'),
                ),
              ),
            ),
            const Divider(height: 40),
            const Text(
                "Lorem ipsum ...... laborum."),
          ]));
    }

This is how the bottom sheet will look after being populated by the widgets mentioned. The container contains an image widget and a text widget to display sample text.

The bottom sheet will work fine for most cases but if you want the sheet to take up the full space and needed the content inside to be scrollable then, we need to wrap the container with **DraggableScrollableSheet **and replace the inside container with ListView.

 class _CustomBottomSheetState extends State<CustomBottomSheet> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text("Geek Aid"),
            centerTitle: true,
          ),
          body: Center(
            child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
              ElevatedButton(
                  onPressed: () => showModalBottomSheet(
                      backgroundColor: Colors.transparent, //New
                      isScrollControlled: true, //New
                      context: context,
                      builder: (context) => buildSheet(context)),
                  child: const Text("Bottom Sheet"))
            ]),
          ),
        );
      }

      Widget buildSheet(context) {
        return DraggableScrollableSheet(
            initialChildSize: 0.6, //New
            maxChildSize: 0.9, // New
            minChildSize: 0.5, //New
            builder: (_, controller) => Container( //New
                  color: Colors.white,
                  padding: const EdgeInsets.all(16),
                  child: ListView( //New
                    controller: controller, //New
                    children: [
                      Container(
                        width: 200,
                        height: 200,
                        decoration: const BoxDecoration(
                          shape: BoxShape.circle,
                          image: DecorationImage(
                            fit: BoxFit.fitHeight,
                            image: AssetImage('assets/logo.png'),
                          ),
                        ),
                      ),
                      const Divider(height: 40),
                      const Text( "Lorem ... laborum."),
                      const SizedBox(height: 20,),
                      const Text("Lorem  ... laborum.")
                    ],
                  ),
                ));
      }
    }

FullScreen BottomSheet Flutter

To make the bottom sheet scrollable first we need to make the

isScrollControlled to true and make the background transparent to enhance the UI look in the showModalBottomSheet.

In the buildSheet, we wrap the container with DraggableScrollableSheet, from the builder we get context and scrollController. We change the column to show ListView and pass the scrollController to the ListView.

  • initialChildSize: This set the initial height of the bottom sheet when the sheet appears every time on the event it is mapped to.

  • maxChildSize: This set the maximum height of the bottom sheet that can cover by the bottom sheet.

  • minChildSize: This set the minimum height of the bottom sheet, the bottom sheet collapsed when the height of the sheet drops below the minChildSize.

This solves some of our problems but comes with its own, Now if you have noticed the bottom sheet did not close when clicked outside the sheet. To achieve this there is a workaround that we can use.

class _CustomBottomSheetState extends State<CustomBottomSheet> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          .
          .
          body: Center(
            child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
              ElevatedButton(
                  onPressed: () => showModalBottomSheet(
                      .
                      .
                      builder: (context) =>
                          makeDismissible(child: buildSheet(), context: context)), //new
                  child: const Text("Bottom Sheet"))
            ]),
          ),
        );
      }

    //New
    Widget makeDismissible(
            {required Widget child, required BuildContext context}) =>
        GestureDetector(
          behavior: HitTestBehavior.opaque,
          onTap: () => Navigator.pop(context),
          child: GestureDetector(
            onTap: () {},
            child: child,
          ),
        );

makeDismissble is a widget that I have to build to solve the above problem, there are two parameters required a child that will be our bottom sheet (buildSheet) widget and context for the navigator to work.

Replace the buidSheet in showModalBottomSheet from makeDismissible and pass buildSheet and context as parameters.

Conclusion

In this article, I tried to explain how to use showModalBottomSheet, which you can modify according to your own. We explore how to make it scrollable and how to achieve the tap close feature.

I hope this article will help you to learn about the bottom sheet and the different ways you can use it in your apps.

If I got something wrong, Inform me on my social media accounts and feel free to contact me and help me to correct it, I would love to improve and rectify my mistake.

❤️❤️ Thanks for reading this article ❤️❤️

Did you find this article valuable?

Support Geek Aid by becoming a sponsor. Any amount is appreciated!