It is easier to us SlidingUpPanel on Flutter

A draggable Flutter widget that makes implementing a SlidingUpPanel much easier!

Installing

Add the following to your pubspec.yaml file:

dependencies:
  sliding_up_panel: ^0.3.3

Simple Usage

There are two ways which the SlidingUpPanel can easily be added to your project.

  1. Using the SlidingUpPanel as the root widget for the body (recommended).
  2. Nesting the SlidingUpPanel

SlidingUpPanel as the Root (recommended)

This method is recommended as it allows for the least interference with the behavior of other UI elements. For example:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text("SlidingUpPanelExample"),
    ),
    body: SlidingUpPanel(
      panel: Center(
        child: Text("This is the sliding Widget"),
      ),
      body: Center(
        child: Text("This is the Widget behind the sliding panel"),
      ),
    ),
  );
}


Nesting the SlidingUpPanel

This method isn’t recommended but can still be used. Only use this to avoid refactoring large chunks of code or to implement custom scrolling behavior. For example, the SlidingUpPanel can be nested inside of a Stack (note that there are many other possible implementations that vary on a case-by-case basis).

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text("SlidingUpPanelExample"),
    ),
    body: Stack(
      children: <Widget>[
        Center(child: Text("This is the Widget behind the sliding panel"),),

        SlidingUpPanel(
          panel: Center(child: Text("This is the sliding Widget"),),
        )
      ],
    )
  );
}

Screenshots

Both methods produce the same result:

Darkening the Body as the Panel Opens

If desired, the body can be darkened as the panel is opened by setting backdropEnabled to true. You can also customize the backdropColorbackdropOpacity, and backdropTapClosesPanel. For example:

@override
Widget build(BuildContext context){
  return Material(
    child: SlidingUpPanel(
      backdropEnabled: true,
      panel: Center(
        child: Text("This is the sliding Widget"),
      ),
      body: Scaffold(
        appBar: AppBar(
          title: Text("SlidingUpPanelExample"),
        ),
        body:  Center(
          child: Text("This is the Widget behind the sliding panel"),
        ),
      ),
    ),
  );
}

Notice how the Scaffold is nested inside of the SlidingUpPanel. This because the backdrop is rendered only over the body of the SlidingUpPanel. As a result, if we want the backdrop to appear over the AppBar, then we must nest the Scaffold this way.

Displaying a Different Child When the Panel is Closed

By assigning a non-null Widget to the collapsed property, you can add a Widget that displays overtop the panel when collapsed. As the panel is opened, this Widget will fade out to display the panel underneath. For example:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text("SlidingUpPanelExample"),
    ),
    body: SlidingUpPanel(
      panel: Center(
        child: Text("This is the sliding Widget"),
      ),
      collapsed: Container(
        color: Colors.blueGrey,
        child: Center(
          child: Text(
            "This is the collapsed Widget",
            style: TextStyle(color: Colors.white),
          ),
        ),
      ),
      body: Center(
        child: Text("This is the Widget behind the sliding panel"),
      ),
    ),
  );
}

Rounding the Borders

Modern design principles (especially in the Material Design Refresh) emphasize rounded borders. A similar effect can be easily achieved by providing a non-null BorderRadiusGeometry to the borderRadius property. Note that this only curves the border on the underlying panel sheet: any children passed to panel or collapsed must also have their borders curved separately in order to achieve a uniform effect. For example:

@override
Widget build(BuildContext context) {
  BorderRadiusGeometry radius = BorderRadius.only(
    topLeft: Radius.circular(24.0),
    topRight: Radius.circular(24.0),
  );

  return Scaffold(
    appBar: AppBar(
      title: Text("SlidingUpPanelExample"),
    ),
    body: SlidingUpPanel(
      panel: Center(
        child: Text("This is the sliding Widget"),
      ),

      collapsed: Container(
        decoration: BoxDecoration(
          color: Colors.blueGrey,
          borderRadius: radius
        ),
        child: Center(
          child: Text(
            "This is the collapsed Widget",
            style: TextStyle(color: Colors.white),
          ),
        ),
      ),

      body: Center(
        child: Text("This is the Widget behind the sliding panel"),
      ),

      borderRadius: radius,
    ),
  );
}

Creating A Floating Effect

To create a fully custom effect, the default panel sheet can be completely hidden and only the children rendered (i.e. only bodypanel, and collapsed are rendered). To do this, set the renderPanelSheet property to false. For example, to create a floating effect:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text("SlidingUpPanelExample"),
    ),
    body: SlidingUpPanel(
      renderPanelSheet: false,
      panel: _floatingPanel(),
      collapsed: _floatingCollapsed(),
      body: Center(
        child: Text("This is the Widget behind the sliding panel"),
      ),
    ),
  );
}

Widget _floatingCollapsed(){
  return Container(
    decoration: BoxDecoration(
      color: Colors.blueGrey,
      borderRadius: BorderRadius.only(topLeft: Radius.circular(24.0), topRight: Radius.circular(24.0)),
    ),
    margin: const EdgeInsets.fromLTRB(24.0, 24.0, 24.0, 0.0),
    child: Center(
      child: Text(
        "This is the collapsed Widget",
        style: TextStyle(color: Colors.white),
      ),
    ),
  );
}

Widget _floatingPanel(){
  return Container(
    decoration: BoxDecoration(
      color: Colors.white,
      borderRadius: BorderRadius.all(Radius.circular(24.0)),
      boxShadow: [
        BoxShadow(
          blurRadius: 20.0,
          color: Colors.grey,
        ),
      ]
    ),
    margin: const EdgeInsets.all(24.0),
    child: Center(
      child: Text("This is the SlidingUpPanel when open"),
    ),
  );
}

Note that a similar effect can be created by simply adding a margin to the SlidingUpPanel.

Adding Scrollable Elements to the Sliding Panel

The panel itself can contain Scrollable elements. However, it’s important to note that when other Scrollable Widgets are nested inside of the panel, you need to incorporate some empty space (i.e. non-scrolling space) at the top which the user can swipe down on to close the panel. For example:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text("SlidingUpPanelExample"),
    ),
    body: SlidingUpPanel(
      color: Colors.blueGrey,
      panel: _scrollingList(),
      body: Center(
        child: Text("This is the Widget behind the sliding panel"),
      ),
    ),
  );
}

Widget _scrollingList(){
  return Container(
    //adding a margin to the top leaves an area where the user can swipe
    //to open/close the sliding panel
    margin: const EdgeInsets.only(top: 36.0),

    color: Colors.white,
    child: ListView.builder(
      itemCount: 50,
      itemBuilder: (BuildContext context, int i){
        return Container(
          padding: const EdgeInsets.all(12.0),
          child: Text("$i"),
        );
      },
    ),
  );
}

Using the PanelController

At times, it can be useful to manually change the state of the SlidingUpPanel. This can be easily achieved by using a PanelController and attaching it to an instance of the SlidingUpPanel. Note that since the PanelController modifies the state of a SlidingUpPanel, these methods can only be called after the SlidingUpPanel has been rendered.

PanelController _pc = new PanelController();

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text("SlidingUpPanelExample"),
    ),
    body: SlidingUpPanel(
      controller: _pc,
      panel: Center(
        child: Text("This is the sliding Widget"),
      ),
      body: _body(),
    ),
  );
}

Widget _body(){
  return Container(
    child: Column(
      children: <Widget>[
        RaisedButton(
          child: Text("Open"),
          onPressed: () => _pc.open(),
        ),
        RaisedButton(
          child: Text("Close"),
          onPressed: () => _pc.close(),
        ),
        RaisedButton(
          child: Text("Show"),
          onPressed: () => _pc.show(),
        ),
        RaisedButton(
          child: Text("Hide"),
          onPressed: () => _pc.hide(),
        ),
      ],
    ),
  );
}

Thanks akshathjain for wonderful article.
Find more details on https://pub.dartlang.org/packages/sliding_up_panel

Leave a Comment