How to create a sliding up panel in Flutter

If you are in a situation where you want to display fewer content on the UI but want to display details for users at the same time then sliding up panel is what you’re looking for.

Sliding up panel is a draggable panel that opens when the user slides up to display additional data and closes by sliding back down.

An example that we always see is Google Maps which displays a bottom panel that’s used to show what’s in the current area. You might want to use sliding up panel to show product details to keep the main UI tidy and clean.

In this post, we’ll discuss how to create a sliding up panel in Flutter apps.

Installing the package

Add the dependency to the pubspec.yaml file in your project by running the following command in the terminal

flutter pub add sliding_up_panel

or, manually add it by adding the following code under the dependencies section in pubspec.yaml file

sliding_up_panel: ^2.0.0+1

Then, run flutter pub get and you’re all set.

Flutter sliding up panel example

In this example, we’ll design a page that shows the description of a course and displays the course structure when the user swipes up the sliding panel.

Before we begin, I want to explain a little bit on what we’ll be doing in the next steps. We’ll create 4 dart files to handle the sliding up panel and keep our code organized. These four files are:

  • main_page.dart : The main page where we’ll use the other 3 widgets and implement the sliding panel
  • background.dart : The widget which is displayed in the main page
  • panel_content.dart : The widget which is displayed when the panel is open
  • collapsed_panel.dart : The widget that is shown when the panel is collapsed.

Let’s start by creating the background page that’ll display the content on the main page of our app. This widget basically displays the course title with a picture

class BackgroundWidget extends StatelessWidget {
  const BackgroundWidget({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Container(
      child:  Column(
          children: [
            Container(
              margin: const EdgeInsets.only(top:20),
              width: 100,
              height: 100,
              child: Image.asset(
                'assets/flutter.png'
              ),
            ),
            SizedBox(height: 10),
            Text(
              'Flutter Course',
              style: TextStyle(
                fontSize: 40,
                fontWeight: FontWeight.bold,
                color: Colors.black54
              ),
            ),
            SizedBox(height: 10),
            Text(
              'This course is for beginners with programming background. \n'
                  'If you don\'t have that, we recommend you to start with basic dart course first'
                  ,
              textAlign: TextAlign.center,
              style: TextStyle(
                  fontSize: 20,
                  color: Colors.black54,

              ),
            ),

          ],

      ),
    );
  }
}

Next, we’ll create the panel content which shows a list of the course’s videos with their title and duration.

class PanelWidget extends StatelessWidget {
  const PanelWidget({Key? key, required this.scrollController}) : super(key: key);
  final ScrollController scrollController;
  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: const EdgeInsets.all(16),
      controller: scrollController,
      children: [
        Text('Course Material', style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold),),
        SizedBox(height: 20),
        Row(
          children: [
            Container(
              width: 80,
              height: 30,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(25),
                color: Colors.blue.withOpacity(0.2),
              ),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  Icon(
                    Icons.timelapse,
                    color: Colors.indigo,
                  ),

                  Text(
                    '30:00',
                    style: TextStyle(
                      color: Colors.indigo,
                      fontWeight: FontWeight.bold,
                      fontSize: 15
                    ),
                  ),
                ],
              ),
            ),
            SizedBox(width: 20,),
            Container(
              width: 80,
              height: 30,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(25),
                color: Colors.blue.withOpacity(0.2),
              ),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  Text(
                    'Beginner',
                    style: TextStyle(
                        color: Colors.indigo,
                        fontWeight: FontWeight.bold,
                        fontSize: 15
                    ),
                  ),
                ],
              ),
            )
          ],
        ),
        SizedBox(height: 20),
        Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Container(
                  width: 50,
                  height: 50,
                  decoration: BoxDecoration(
                    image: DecorationImage(
                      image: AssetImage('assets/flutter.png',),
                      fit: BoxFit.fitWidth
                    ),
                  ),
                ),
                SizedBox(width: 5),
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Introduction to Widgets',
                      style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                    ),
                    SizedBox(height: 5,),
                    Text('10 minutes',style: TextStyle(fontSize: 16)),
                    Container(
                      margin: EdgeInsets.symmetric(vertical: 5),
                      width: 240,
                      height: 4,
                      color: Colors.grey[200],
                    )
                  ],
                ),
                SizedBox(width: 15),
                Icon(
                  Icons.navigate_next,
                  size: 50,
                  color: Colors.indigo[300],
                ),

              ],
            )
          ],
        ),
        SizedBox(height: 20),
        Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Container(
                  width: 50,
                  height: 50,
                  decoration: BoxDecoration(
                    image: DecorationImage(
                        image: AssetImage('assets/flutter.png',),
                        fit: BoxFit.fitWidth
                    ),
                  ),
                ),
                SizedBox(width: 5),
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Introduction to Layouts',
                      style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                    ),
                    SizedBox(height: 5,),
                    Text('15 minutes',style: TextStyle(fontSize: 16)),
                    Container(
                      margin: EdgeInsets.symmetric(vertical: 5),
                      width: 240,
                      height: 4,
                      color: Colors.grey[200],
                    )
                  ],
                ),
                SizedBox(width: 15),
                Icon(
                  Icons.navigate_next,
                  size: 50,
                  color: Colors.indigo[300],
                ),

              ],
            )
          ],
        ),
        SizedBox(height: 20),
        Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Container(
                  width: 50,
                  height: 50,
                  decoration: BoxDecoration(
                    image: DecorationImage(
                        image: AssetImage('assets/flutter.png',),
                        fit: BoxFit.fitWidth
                    ),
                  ),
                ),
                SizedBox(width: 5),
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Stateful Vs Stateless widgets',
                      style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                    ),
                    SizedBox(height: 5,),
                    Text('5 minutes',style: TextStyle(fontSize: 16)),
                    Container(
                      margin: EdgeInsets.symmetric(vertical: 5),
                      width: 240,
                      height: 4,
                      color: Colors.grey[200],
                    )
                  ],
                ),
                SizedBox(width: 15),
                Icon(
                  Icons.navigate_next,
                  size: 50,
                  color: Colors.indigo[300],
                ),

              ],
            )
          ],
        )

      ],
    );
  }
}

Then, let’s create the collapsed panel widget. This is a widget that’s shown whenever the panel is collapsed and it only contains a text

class CollapsedPanel extends StatelessWidget {
  const CollapsedPanel({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
          color: Colors.blue[500],
          borderRadius: BorderRadius.only(
              topRight: Radius.circular(30),
              topLeft: Radius.circular(30)
          )),
      child: Center(
        child: Text(
          'Swipe up for details',
          style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
        ),
      ),
    );
  }
}

Finally, let’s create the main page that’ll handle the sliding panel. First thing we need to do is to import the sliding panel library

import 'package:sliding_up_panel/sliding_up_panel.dart';

 

It’s recommended that the sliding up panel is used as the root widget in the widgets hierarchy. Therefore, we’ll use SlidingUpPanel() as the body of the Scaffold. Sliding Up Panel has several properties which includes but not limited to:

  • body: The widget underneath the sliding panel and it automatically sizes itself to full screen.
  • collapsed: The widget displayed on top of the panel when collapsed and it fades out as the panel opens.
  • panelBuilder: Provides a ScrollController to attach to a scrollable object in the panel that links the panel position with the scroll position. Useful for implementing an infinite scroll behavior.
  • minHeight: The height of the sliding panel when fully collapsed.
  • maxHeight: The height of the sliding panel when fully open.
  • borderRadius: If non-null, the corners of the sliding panel sheet are rounded by this.
  • border: A border to draw around the sliding panel sheet.
  • color: The color to fill the background of the sliding panel sheet.
  • boxShadow: A list of shadows cast behind the sliding panel sheet.
  • padding: The amount to inset the children of the sliding panel sheet.
  • margin: The empty space that surrounds the sliding panel sheet.
  • backDropEnabled: If true, shows a darkening shadow over the body as the panel slides open.
  • backDropColor: Shows a darkening shadow of this Color over the body as the panel slides open.
  • controller: controls the state of the panel.
  • onPanelOpened: a callback when the panel is opened.
  • onPanelClosed:  a callback when the panel is collapsed.
  • isDraggable: True by default. It allows the user to drag the panel up and down.  You can set this to false if you want to prevent the user from being able the drag the panel up and down.
  • slideDirection: Either SlideDirection.UP or SlideDirection.DOWN

Now that we understand the sliding up panel properties, let’s continue the code . We’ll set the background.dart widget to be the body of the panel and collapsed.dart as the collapsed widget. As for the panel widget, we’ll create a method that we’ll call in the panel builder.

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Sliding up panel example'),
        centerTitle: true,
      ),
      body: SlidingUpPanel(
        borderRadius: BorderRadius.only(
          topLeft: Radius.circular(30),
          topRight: Radius.circular(30)
        ),
        backdropEnabled: true,
        panelBuilder: (scrollController) =>  buildSlidingPanel(scrollController: scrollController)
        ,
        body: BackgroundWidget(),
        collapsed: CollapsedPanel(),
      ),
    );
  }
  
  Widget buildSlidingPanel({required ScrollController scrollController}) {
    return PanelWidget(scrollController: scrollController);
  }
}

Conclusion

Sliding up panel adds a touch of attraction to the app as it helps you keep your UI simple and organize yet you can display additional details to your users. In this example we learned how to create the sliding up panel as a PRO!

I hope this post I was able to guide you how to implement sliding up panel in your Flutter apps.

Please don’t hesitate to support this blog with a like and share if you find its content useful. If you wish to learn more about Flutter programming, you can access a whole Flutter category with plenty of useful topics related to it.

Also, don’t forget to like and share my Facebook page, share the post with those who care to learn, and subscribe to my blog to be one of the firsts to know about my newest posts!

Thank you and happy coding!

Oh hi there!
It’s nice to meet you.

Sign up to receive awesome content in your inbox, every month.

Let's Do This!

2 thoughts on “How to create a sliding up panel in Flutter

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top