Introduction
In this tutorial, we are going to learn about the
DraggableScrollableSheet widget. It is a widget that responds to user gestures. When the user drags from the bottom of the screen in the upward direction, the widget opens up and when scrolls down the widget close.
The final app will look as follows
![]() |
Final App |
DraggableScrollableSheet
It is a widget that scrolls up and down of the viewport or screen according to the user's screen gestures. This widget becomes handy when you want to give some extra details which are lengthy content but don't want to navigate to a new screen. You might have come across many apps that implement the same thing. So let us learn to implement DraggableScrollableSheet in our own app.
Approach
The approach of our project is very simple. In our app, we are going to
display some names of countries
with the help of the ListView.builder and
ListTile widgets. The data will be initialized when we will set up
our project.
Now when the user taps on any of the ListTile, the
DraggableScrollableSheet widget will show the details of the selected tile. By default, it will show the details of the first item index.
Table of Contents
- DraggableScrollableSheet
- Project Setup
- Create our ListTile
- Implement DraggableScrollableSheet widget
- Some more features
- Conclusion
Project Setup
DraggableScrollableSheet widget comes with the Flutter framework only. Hence
we don't need to install any other package.
Create a new project and let us start our tutorial.
In the main.dart file, the code should be as follows.
import 'dart:html'; import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'All About Flutter', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: MaterialColor( Color.fromRGBO(255, 72, 0, 1).value, { 50: Color.fromRGBO(255, 72, 0, 1), 100: Color.fromRGBO(255, 72, 0, 1), 200: Color.fromRGBO(255, 72, 0, 1), 300: Color.fromRGBO(255, 72, 0, 1), 400: Color.fromRGBO(255, 72, 0, 1), 500: Color.fromRGBO(255, 72, 0, 1), 600: Color.fromRGBO(255, 72, 0, 1), 700: Color.fromRGBO(255, 72, 0, 1), 800: Color.fromRGBO(255, 72, 0, 1), 900: Color.fromRGBO(255, 72, 0, 1), }, ), ), home: HomePage(), ); } } class HomePage extends StatefulWidget { const HomePage({Key? key}) : super(key: key); @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { List<String> countryName = ['India', 'UK', 'USA']; List<String> countryNationalGame = ['Hockey', 'Cricket', 'Baseball']; List<String> countryGDP = ['2.87', '2.83', '21.43']; List<String> countryNationalAnimal = ['Tiger', 'Lion', 'American bison']; int selectedTile = 0; @override Widget build(BuildContext context) { return Scaffold(
backgroundColor: Colors.amberAccent,
appBar: AppBar( title: Text("Draggable Scrollable Sheet"), ), body: ListView.builder( itemCount: 3, itemBuilder: (context, index) { return ListTile(); }, ), ); } }
Project Contents:-
- Some data about three countries which we will display in our app.
- A variable selectedTile which will be updated when the user selects any ListTile
- An AppBar
- A ListView.builder
So we have set up our starting project.
Create our ListTile
Currently, our ListTile is empty. We will add the name of the country in a
Text widget and also set up our onTap function.
Here is our most basic setup with a little style.
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.all(8.0),
child: ListTile(
onTap: () {
setState(() => selectedTile = index);
print(selectedTile);
},
title: Text(countryName[index]),
tileColor: Colors.orange[100],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0),
),
),
);
},
Most things are simple. When the user taps on any of the tiles, we call the
setState function which updates the index of the selected tile.
Run the app and the result will be as follows.
![]() |
App with ListView.builder |
Now we will create our DraggableScrollableSheet widget. But before
that, we have to wrap our ListView.builder inside the
Stack widget. This is because the
DraggableScrollableSheet widget will be displayed above over
ListView and not below our ListView.
So wrap it with the Stack widget.
Stack(
children: [
ListView.builder(
itemCount: 3,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.all(8.0),
child: ListTile(
onTap: () {
setState(() => selectedTile = index);
print(selectedTile);
},
title: Text(countryName[index]),
tileColor: Colors.orange[100],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0),
),
),
);
},
),
],
),
In the next section, we are going to implement the
DraggableScrollableSheet widget.
Implement DraggableScrollableSheet
We will show our DraggableScrollableSheet widget above our
ListView.builder
widget.
Inside the Stack widget, children field, we will create
our DraggableScrollableSheet widget.
The index of DraggableScollableSheet index inside the Stack widget should be next to ListView.builder.
Let us learn how it works.
DraggableScollableSheet widget contains on required field and that is
the builder function.
builder: (context, scrollController) {}
Here we return the widget that we want to display. We will display the details of the country that is selected using the selectedTile variable. The builder function also has a scollController which we will provide to our ListView to
give it an animation effect of scrolling.
It has many important parameters. They are listed below:-
- initialChildSize: Takes double value from 0 - 1.0 with default value of 0.5. It is the percentage of the screen to be occupied when the first widget is rendered.
- minChildSize: Takes double value from 0 - 1.0 with default value of 0.25. It is the percentage of the screen to be occupied that the child widget will display even if the user drags down it completely.
- maxChildSize: Takes double value from 0 - 1.0 with default value of 1.0. It is the percentage of the screen to be occupied that the child widget will display even if the user drags up it completely.
I will initialize the parameters as
- initialChildSize: .25,
- minChildSize: .1,
- maxChildSize: .8,
Now here is the code with some style.
DraggableScrollableSheet( initialChildSize: .25, minChildSize: .1, maxChildSize: .8, builder: (context, scrollController) { return ClipRRect( borderRadius: BorderRadius.only( topLeft: Radius.circular(12.0), topRight: Radius.circular(12.0)), child: Container( decoration: BoxDecoration( color: Colors.white, ), child: ListView( controller: scrollController, children: [ Container( color: Colors.white, child: ListTile( title: Text("Country GDP (2019)"), subtitle: Text( countryGDP[selectedTile], ), ), ), ListTile( title: Text("Country National Game"), subtitle: Text( countryNationalGame[selectedTile], ), ), ListTile( title: Text("Country National Animal"), subtitle: Text( countryNationalAnimal[selectedTile], ), ), ], ), ), ); }, ),
We have rounded the corners of the DraggableScrollableSheet. Also, we have
assigned the scrollController to the controller field
of ListView we have created in our app.
![]() |
Final App |
We have finished our app implementing the DraggableScollableSheet widget. Our widget is also animating. In case you have missed anywhere, here is the full code.
import 'dart:html'; import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'All About Flutter', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: MaterialColor( Color.fromRGBO(255, 72, 0, 1).value, { 50: Color.fromRGBO(255, 72, 0, 1), 100: Color.fromRGBO(255, 72, 0, 1), 200: Color.fromRGBO(255, 72, 0, 1), 300: Color.fromRGBO(255, 72, 0, 1), 400: Color.fromRGBO(255, 72, 0, 1), 500: Color.fromRGBO(255, 72, 0, 1), 600: Color.fromRGBO(255, 72, 0, 1), 700: Color.fromRGBO(255, 72, 0, 1), 800: Color.fromRGBO(255, 72, 0, 1), 900: Color.fromRGBO(255, 72, 0, 1), }, ), ), home: HomePage(), ); } } class HomePage extends StatefulWidget { const HomePage({Key? key}) : super(key: key); @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { List<String> countryName = ['India', 'UK', 'USA']; List<String> countryNationalGame = ['Hockey', 'Cricket', 'Baseball']; List<String> countryGDP = ['2.87', '2.83', '21.43']; List<String> countryNationalAnimal = ['Tiger', 'Lion', 'American bison']; int selectedTile = 0; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.amberAccent, appBar: AppBar( title: Text("Draggable Scrollable Sheet"), ), body: Stack( children: [ ListView.builder( itemCount: 3, itemBuilder: (context, index) { return Padding( padding: EdgeInsets.all(8.0), child: ListTile( onTap: () { setState(() => selectedTile = index); print(selectedTile); }, title: Text(countryName[index]), tileColor: Colors.orange[100], shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(5.0), ), ), ); }, ), DraggableScrollableSheet( initialChildSize: .25, minChildSize: .1, maxChildSize: .8, builder: (context, scrollController) { return ClipRRect( borderRadius: BorderRadius.only( topLeft: Radius.circular(12.0), topRight: Radius.circular(12.0)), child: Container( decoration: BoxDecoration( color: Colors.white, ), child: ListView( controller: scrollController, children: [ Container( color: Colors.white, child: ListTile( title: Text("Country GDP (2019)"), subtitle: Text( countryGDP[selectedTile], ), ), ), ListTile( title: Text("Country National Game"), subtitle: Text( countryNationalGame[selectedTile], ), ), ListTile( title: Text("Country National Animal"), subtitle: Text( countryNationalAnimal[selectedTile], ), ), ], ), ), ); }, ), ], ), ); } }
Conclusion
We have made our DraggableScrollableSheet widget. It has all the modern features of the bottom sheet that we come across many apps. Hope you liked the tutorial. If you have any doubts, please comment below.
Comments
Post a Comment
If you have any problem or doubt please comment.