Custom Draggable Bottom Sheet in Flutter
Tags: flutter, flutterdevelopment, programming, frontenddevelpment
Published: 2022-03-26 12:30:38

Hey 👋!
Are you looking for Draggable bottom sheet in flutter? Then you have landed at the right place.
First of all let's see how does **Draggable bottom sheet** look like
 {% youtube 2Ard8s6R5Kw %}

Let's code the approach and the divide the whole section in small chunks of steps
**Step 1: Code the boilerplate code** 
     Declare a global boolean variable named as isSwipeUp, initialize with _false_ 
```dart

import 'package:flutter/material.dart';
bool isSwipeUp =false;
void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Home(),
    );
  }
}

```

**Step 2: Write code for home page**
Creating Home() as StatefulWidget 
As we are placing on widget on other widget so we our using [Stack()](https://api.flutter.dev/flutter/widgets/Stack-class.html)

In stack element are placed one on other, last element will be on top.
![Stack Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lt8uvny2svq5626nswjw.png)
In Stack(), We will use two different Widgets :

- MainScreen()

- CustomBottomSheet()

```dart
class Home extends StatefulWidget {
  const Home({Key? key}) : super(key: key);

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return SafeArea(
      child: Scaffold(
        body: Container(
          color: Colors.black26,
          height: size.height,
          width: size.width,
          child: Stack(
            children: [
              MainPage(), // [Will create in next step]
              Positioned(
                top: size.height * 0.8, //position to be changed  
                  child: const CustomBottomSheet() // [Will create in next step]
               )
            ],
          ),
        ),
      ),
    );
  }
}
```
 
**Step 3: Create MainScreen()**
MainScreen will be very simple as it has only one Container() with a single child with Text() => "HomePage" with some sort of styling and center Alignment
```dart
class MainPage extends StatelessWidget {
  const MainPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.amber,
      child: const Center(child: Text("HomePage",style: TextStyle(color: Colors.white,fontSize: 22),),),
    );
  }
}
```
 Let's jump to next step

**Step 4: Creating CustomBottomSheet()**
CustomBottomSheet has a Container(), having full width and half height of screen with rounded corner at top edges and some sort of styling.

```dart
class CustomBottomSheet extends StatefulWidget {
  const CustomBottomSheet({Key? key}) : super(key: key);

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

class _CustomBottomSheetState extends State<CustomBottomSheet> {
  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return Container(
      height: size.height * 0.5,
      width: size.width,
      decoration: const BoxDecoration(
          gradient: LinearGradient(colors: [
            Color.fromRGBO(26, 41, 128, 100),
            Color.fromRGBO(42, 178, 252, 100),
          ]),
          borderRadius: BorderRadius.only(
              topLeft: Radius.circular(50), topRight: Radius.circular(50))),
              child: Align(alignment: Alignment.topCenter,
              child: (isSwipeUp)
                    ? Icon(
                        Icons.expand_more_outlined,
                        size: 30,
                        color: Colors.white,
                      )
                    : Icon(
                        Icons.expand_less_outlined,
                        size: 30,
                        color: Colors.white,
                      ),
              ),
    );
  }
}
```
Now at this stage of our App looks like

![App](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7buhj03ns2gl1e71fzdy.png)

**Step 5: Adding GestureDetector on CustomBottomSheet() for making it Draggable.**

Now we have to detect gesture of dragging/ Swiping 
But Don't take worries as flutter have an awesome widget [GestureDetector()](https://api.flutter.dev/flutter/widgets/GestureDetector-class.html) 
GestureDetector() helps to detect any kind of gesture on Widget and has various properties but we will use some only.

Adding GestureDetector() on CustomBottomSheet() in Stack 

```dart
GestureDetector(
           onPanEnd: (details) {
                  print(details.velocity.pixelsPerSecond.dy.toString());
                  print(details.velocity.pixelsPerSecond.dx.toString());
           if (details.velocity.pixelsPerSecond.dy > -100) {
                    setState(() {
                      isSwipeUp = true;
                    });
                  } 

               else {
                    setState(() {
                      isSwipeUp = false;
                    });
                  }
             },
                   child: const CustomBottomSheet())
```
Now changing position of **CustomBottomSheet()** as **isSwipeUp** changes
As the transition should be smooth so we will replace **Positioned()** to **AnimatedPositioned()** with duration 400 milliseconds 
**Positioned➡➡ AnimatedPositioned**
     

```dart 
top: !isSwipeUp? size.height *0.5:size.height * 0.8,
```
whole components looks like:-

```dart
AnimatedPositioned(
       curve: Curves.decelerate,
        duration: const Duration(milliseconds: 400),
            top: !isSwipeUp? size.height *0.5:size.height * 0.8,
                 child: GestureDetector(
                    onPanEnd: (details) {           print(details.velocity.pixelsPerSecond.dy.toString());
           if (details.velocity.pixelsPerSecond.dy > -100) {
                    setState(() {
                      isSwipeUp = true;
                    });
                  } else {
                    setState(() {
                      isSwipeUp = false;
                    });
                  }
                },
                      child: const CustomBottomSheet())
           )
```
**Our task is completed🙌🙌.**

**[Full code:-](https://github.com/raj4477/Templates/blob/main/CustomDraggableBottomSheet.dart)**

Catch me on **[LinkedIn](https://www.linkedin.com/in/ritik-raj-66b523206/)**