DEV Community

Cover image for Custom Draggable Bottom Sheet in Flutter
Ritik Raj
Ritik Raj

Posted on

Custom Draggable Bottom Sheet in Flutter

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

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


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(),
    );
  }
}

Enter fullscreen mode Exit fullscreen mode

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()

In stack element are placed one on other, last element will be on top.
Stack Image
In Stack(), We will use two different Widgets :

  • MainScreen()

  • CustomBottomSheet()

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]
               )
            ],
          ),
        ),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

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

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),),),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

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.

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,
                      ),
              ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Now at this stage of our App looks like

App

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()
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

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())
Enter fullscreen mode Exit fullscreen mode

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

top: !isSwipeUp? size.height *0.5:size.height * 0.8,
Enter fullscreen mode Exit fullscreen mode

whole components looks like:-

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())
           )
Enter fullscreen mode Exit fullscreen mode

Our task is completed๐Ÿ™Œ๐Ÿ™Œ.

Full code:-

Catch me on LinkedIn

Top comments (0)