Jesse
Jesse

Reputation: 3050

Disable drag down to close showModalBottomSheet

How do I disable / escape drag down gesture within the Bottom Sheet Modal so the user can interact within the modal without accidentally closing the modal?

Updated below with the actual modal bottom sheet.

return showModalBottomSheet(
    context: context,
    builder: (BuildContext context) {
        ...
    }
}

Upvotes: 23

Views: 20781

Answers (4)

crookshanksacademy.com
crookshanksacademy.com

Reputation: 564

I wanted a bottomsheet that is draggable up and down, but does not close on dragging down. My thought was what if as soon as it closes, I call it again? Here, recursion comes to rescue. So, first of all I created a function for my modalBottomSheet.

Future modalBottomSheetShow(BuildContext context) {
    return showModalBottomSheet(
      backgroundColor: Colors.transparent,
      context: context,
      builder: (context) => buildSheet(),
      isDismissible: false,
      elevation: 0,
    );
  }

Next, I used .whenComplete() method of showModalBottomSheet() to recursively call the modalBottomSheetShow() function.

  Future modalBottomSheetShow(BuildContext context) {
    return showModalBottomSheet(
      backgroundColor: Colors.transparent,
      context: context,
      builder: (context) => buildSheet(),
      isDismissible: false,
      elevation: 0,
    ).whenComplete(() => modalBottomSheetShow(context));
  }

Next, I simply call the modalBottomSheetShow() whenever I wanted a bottomsheet. It cannot be closed, until the recursion ends. Here is the entire code for reference:

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);
  static const idScreen = "HomePage";
  @override
  State<HomePage> createState() => _HomePageState();
}



  @override
  void initState() {
    super.initState();

    WidgetsBinding.instance.addPostFrameCallback((_) async {
      modalBottomSheetShow(context);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        toolbarHeight: 0,
        elevation: 0,
        backgroundColor: Colors.black,
      ),
    );
  }

  Widget buildSheet() {
    return DraggableScrollableSheet(
      initialChildSize: 0.6,
      builder: (BuildContext context, ScrollController scrollController) {
        return Container(
          decoration: BoxDecoration(color: Colors.white, boxShadow: [
            BoxShadow(
              color: Color(0x6C000000),
              spreadRadius: 5,
              blurRadius: 20,
              offset: Offset(0, 0),
            )
          ]),
          padding: EdgeInsets.all(16),
        );
      },
    );
  }

  Future modalBottomSheetShow(BuildContext context) {
    return showModalBottomSheet(
      backgroundColor: Colors.transparent,
      context: context,
      builder: (context) => buildSheet(),
      isDismissible: false,
      elevation: 0,
    ).whenComplete(() => modalBottomSheetShow(context));
  }
}

Upvotes: 0

Turbo19973
Turbo19973

Reputation: 97

If you still want to have the scroll inside the modal without the user drag and close it, you can use this:

                  showModalBottomSheet(
                    context: context,
                    enableDrag: false,
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.vertical(
                        top: Radius.circular(20),
                      ),
                    ),
                    clipBehavior: Clip.antiAliasWithSaveLayer,
                    builder: (context) => DraggableScrollableSheet(
                      expand: false,
                      initialChildSize: 0.9,
                      minChildSize: 0.5,
                      maxChildSize: 0.9,
                      builder: (context, scrollController) {
                        return SingleChildScrollView(
                          child: new Container(
                            color: Colors.white,
                            child: buildTitleWidget(),
                          ),
                        );
                      },
                    ),
                    isDismissible: false,
                    isScrollControlled: true,
                  );

The trick is not to add scrollController to the SingleChildScrollView

                      builder: (context, scrollController) {
                        return SingleChildScrollView(
                          controller: scrollController            <-- HERE
                          child: new Container(
                            color: Colors.white,
                            child: buildTitleWidget(),
                          ),
                        );
                      },

Upvotes: 3

Raj Singh
Raj Singh

Reputation: 181

you can try to wrap builder's result with GestureDetector with onVerticalDragStart = (_) {}

showModalBottomSheet(
  context: context,
  builder: (context) => GestureDetector(
    child: **any_widget_here**,
    onVerticalDragStart: (_) {},
  ),
  isDismissible: false,
  isScrollControlled: true,
);

Upvotes: 18

Willy
Willy

Reputation: 909

Set enableDrag to false

bool enableDrag

If true, the bottom sheet can dragged up and down and dismissed by swiping downwards.

https://docs.flutter.io/flutter/material/BottomSheet/enableDrag.html

Upvotes: 28

Related Questions