How can I achieve a draggable header in bottomsheet modal?

643 Views Asked by At

In my flutter app, I’m using a pinned header and a listview within a bottomsheet modal.

The problem usually is that when I overscroll, I have to scroll all the way back to be able to dismiss the modal. I would like to drag the header instead to collapse the bottom sheet modal even when the list is overscrolled.

Does anyone know how I can make the header draggable to achieve this effect?

You can find similar behavior in for example "places" section on Snapchat or the "comments" section of YouTube’s mobile app.

Here is a preview: https://imgur.com/a/fxww2IW

Here is a link to my code snippet: https://dartpad.dev/?id=960bf30a2c288ec1a0a48374b6cdbfd3

import 'package:flutter/material.dart';

const Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(
        scaffoldBackgroundColor: darkBlue,
      ),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: ElevatedButton(
            child: const Text('Show modal'),
            onPressed: () => {
              showModalBottomSheet(
                  backgroundColor: Colors.transparent,
                  clipBehavior: Clip.antiAlias,
                  context: context,
                  enableDrag: true,
                  isDismissible: true,
                  isScrollControlled: true,
                  builder: (modalContext) => MyWidget())
            },
          ),
        ),
      ),
    );
  }
}

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return DraggableScrollableSheet(
      initialChildSize: 0.5,
      minChildSize: 0.5,
      maxChildSize: 0.9,
      expand: false,
      builder: (BuildContext context, ScrollController scrollController) =>
          Container(
          color: Colors.white,
          child: CustomScrollView(
            controller: scrollController,
            slivers: [
              const SliverAppBar(
                 title: Text("Header Title"),
                 pinned: true,
              ),
              SliverFillRemaining(
                child: ListView.builder(
                  itemCount: 500,
                  itemBuilder: (BuildContext context, int index) {
                    return ListTile(
                        leading: const Icon(Icons.list),
                        trailing: const Text(
                          "GFG",
                          style: TextStyle(color: Colors.green, fontSize: 15),
                        ),
                        title: Text("List item $index"));
                  }),
              ),
            ],
          ),
        ),
    );
  }
}

I have tried using CustomScrollview with Slivers. I expect that dragging the pinned header downwards will also move the bottomsheet downwards as in the image I have shared in the description

1

There are 1 best solutions below

1
Abdullatif Eida On

Look The solution for your problem is easy make a late ScrollController _scrollController; and put it in your listviewthen put this code in initState

super.initState();
_controller = ScrollController()..addListener(_scrollListener);
void _scrollListener() {`
if (_controller.position.userScrollDirection == ScrollDirection.forward &&
    _controller.position.extentAfter >= _controller.position.maxScrollExtent) {
       Navigator.pop(context);
   }
`}

this mean when my ScrollController go up a little pop out that will close your showModalBottomSheet