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

Overview

sliding_up_panel

pub package GitHub Stars Platform

A draggable Flutter widget that makes implementing a SlidingUpPanel much easier! Based on the Material Design bottom sheet component, this widget works on both Android & iOS.

Example Example App Closed Example App Open


Installing

Add the following to your pubspec.yaml file:

dependencies:
  sliding_up_panel: ^2.0.0+1

Note that v1.0.0 introduced some breaking changes outlined below.


Maintaining sliding_up_panel

Thank you everyone for the support surrounding this project! sliding_up_panel has grown far larger than I could have ever imagined, so parsing through all the feature requests and new issues has taken me more time than I'd like. If you're interested in helping maintain this project, please send me an email at [email protected]. As a sidenote, I'll always try to make sure that this project is compatible with the latest version of Flutter.


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:

Panel Closed Panel Midway Panel Open




Custom Usage

There are several options that allow for more control:

Properties Description
panel The Widget that slides into view. When the panel is collapsed and if collapsed is null, then top portion of this Widget will be displayed; otherwise, collapsed will be displayed overtop of this Widget.
panelBuilder [beta] NOTE: This feature is still in beta and may have some problems. Please open an issue on GitHub if you encounter something unexpected.

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. If panel and panelBuilder are both non-null, panel will be used.
collapsed The Widget displayed overtop the panel when collapsed. This fades out as the panel is opened.
body The Widget that lies underneath the sliding panel. This Widget automatically sizes itself to fill the screen.
header Optional persistent widget that floats above the panel and attaches to the top of the panel. Content at the top of the panel will be covered by this widget. Add padding to the top of the panel to avoid coverage.
footer Optional persistent widget that floats above the panel and attaches to the bottom of the panel. Content at the bottom of the panel will be covered by this widget. Add padding to the bottom of the panel to avoid coverage.
minHeight The height of the sliding panel when fully collapsed.
maxHeight The height of the sliding panel when fully open.
snapPoint [beta] NOTE: This feature is still in beta and may have some problems. Please open an issue on GitHub if you encounter something unexpected.

A point between minHeight and maxHeight that the panel snaps to while animating. A fast swipe on the panel will disregard this point and go directly to the open/close position. This value is represented as a percentage of the total animation distance (maxHeight - minHeight), so it must be between 0.0 and 1.0, exclusive.
border A border to draw around the sliding panel sheet.
borderRadius If non-null, the corners of the sliding panel sheet are rounded by this.
boxShadow A list of shadows cast behind the sliding panel sheet.
color The color to fill the background of the sliding panel sheet.
padding The amount to inset the children of the sliding panel sheet.
margin Empty space surrounding the sliding panel sheet.
renderPanelSheet Set to false to not to render the sheet the panel sits upon. This means that only body, collapsed, and the panel Widgets will be rendered. Set this to false if you want to achieve a floating effect or want more customization over how the sliding panel looks like.
panelSnapping Set to false to disable the panel from snapping open or closed.
backdropEnabled If non-null, 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.
backdropOpacity The opacity of the backdrop when the panel is fully open. This value can range from 0.0 to 1.0 where 0.0 is completely transparent and 1.0 is completely opaque.
backdropTapClosesPanel Flag that indicates whether or not tapping the backdrop closes the panel. Defaults to true.
controller If non-null, this can be used to control the state of the panel.
onPanelSlide If non-null, this callback is called as the panel slides around with the current position of the panel. The position is a double between 0.0 and 1.0 where 0.0 is fully collapsed and 1.0 is fully open.
onPanelOpened If non-null, this callback is called when the panel is fully opened.
onPanelClosed If non-null, this callback is called when the panel is fully collapsed.
parallaxEnabled If non-null and true, the SlidingUpPanel exhibits a parallax effect as the panel slides up. Essentially, the body slides up as the panel slides up.
parallaxOffset Allows for specifying the extent of the parallax effect in terms of the percentage the panel has slid up/down. Recommended values are within 0.0 and 1.0 where 0.0 is no parallax and 1.0 mimics a one-to-one scrolling effect. Defaults to a 10% parallax.
isDraggable Allows toggling of draggability of the SlidingUpPanel. Set this to false to prevent the user from being able to drag the panel up and down. Defaults to true.
slideDirection Either SlideDirection.UP or SlideDirection.DOWN. Indicates which way the panel should slide. Defaults to UP. If set to DOWN, the panel attaches itself to the top of the screen and is fully opened when the user swipes down on the panel.
defaultPanelState The default state of the panel; either PanelState.OPEN or PanelState.CLOSED. This value defaults to PanelState.CLOSED which indicates that the panel is in the closed position and must be opened. PanelState.OPEN indicates that by default the Panel is open and must be swiped closed by the user.


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 backdropColor, backdropOpacity, 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.

Panel Closed Panel Midway Panel Open



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

Panel Closed Panel Midway Panel Open



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

Panel Closed Panel Midway Panel Open



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 body, panel, 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.

Panel Closed Panel Midway Panel Open



Adding Scrollable Elements to the Sliding Panel

The panel itself can contain Scrollable elements. As of v1.0.0, you can link the scroll position of the Scrollable elements with the position of the sliding up panel by using the panelBuilder. For example:

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

Widget _scrollingList(ScrollController sc){
  return ListView.builder(
    controller: sc,
    itemCount: 50,
    itemBuilder: (BuildContext context, int i){
      return Container(
        padding: const EdgeInsets.all(12.0),
        child: Text("$i"),
      );
    },
  );
}

Panel Closed Panel Midway Panel Open



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.

Properties Data Type Permissions Description
panelPosition double Read / Write Evaluates to the current panel position (a value between 0.0 and 1.0) where 0.0 is closed and 1.0 is open. Any value assigned to this property must be between 0.0 and 1.0, inclusive.
isAttached bool Read Determine if the panelController is attached to an instance of the SlidingUpPanel (this property must be true before any other PanelController functions can be used)
isPanelAnimating bool Read Returns whether or not the panel is currently animating.
isPanelOpen bool Read Returns whether or not the panel is open.
isPanelClosed bool Read Returns whether or not the panel is collapsed.
isPanelShown bool Read Returns whether or not the panel is shown/hidden.

Methods Return Type Description
open() Future<void> Opens the sliding panel fully (i.e. to the maxHeight)
close() Future<void> Closes the sliding panel to its collapsed state (i.e. to the minHeight)
hide() Future<void> Hides the sliding panel (i.e. is invisible)
show() Future<void> Shows the sliding panel in its collapsed state (i.e. "un-hide" the sliding panel)
animatePanelToPosition(double value, {Duration duration, Curve curve = Curves.linear}) Future<void> Animates the panel position to the value. The value must between 0.0 and 1.0 where 0.0 is fully collapsed and 1.0 is completely open. (optional) duration specifies the time for the animation to complete. (optional) curve specifies the easing behavior of the animation.
animatePanelToSnapPoint(double value, {Duration duration, Curve curve = Curves.linear}) [beta] Future<void> NOTE: This feature is still in beta and may have some problems. Please open an issue on GitHub if you encounter something unexpected.

Animates the panel position to the snap point. Requires that the SlidingUpPanel snapPoint property is not null. (optional) duration specifies the time for the animation to complete. (optional) curve specifies the easing behavior of the animation.
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(),
        ),
      ],
    ),
  );
}


Breaking Changes

v1.0.0 introduced some breaking changes to the PanelController to better adhere to Dart language conventions. The changes are outlined below.

The following PanelController methods now return Future<void> instead of void:

  • close()
  • open()
  • hide()
  • show()
  • animatePanelToPosition(double value)

The following PanelController methods have changed to Dart properties to better reflect Dart language conventions:

  • setPanelPosition() -> panelPosition [as a setter]
  • getPanelPosition() -> panelPosition [as a getter]
  • isPanelAnimating() -> isPanelAnimating
  • isPanelOpen() -> isPanelOpen
  • isPanelClosed() -> isPanelClosed
  • isPanelShown() -> isPanelShown

For example, here's how you would have previously used setPanelPosition() and getPanelPosition() vs. how you would now use the panelPosition property:

// OLD, no longer supported
print(pc.getPanelPosition()); // print a value between 0.0 and 1.0
pc.setPanelPosition(0.5);     // sets the panelPosition to 0.5
// NEW
print(pc.panelPosition); // print a value between 0.0 and 1.0
pc.panelPosition = 0.5;  // sets the panelPosition to 0.5

And here's how you would have previously called isPanelAnimating() vs. how you would now call isPanelAnimating.

panelController.isPanelAnimating(); // OLD, no longer supported
panelController.isPanelAnimating; // NEW
Comments
  • Infinite height?

    Infinite height?

    First of all, it's great implementation. I have been looking for a widget like this for a while and I had implemented it from scratch but it was no where as smooth as your implementation. I have been playing around with different properties but i am not able to implement it with infinite height or with height that's larger than screen size. I am trying implement it with floating effect, so how would i implement when height is larger than screen size? i want it to scroll/drag as long as there are items. Thanks in advance!

    bug enhancement question 
    opened by siddzankat 29
  • 3 levels of height

    3 levels of height

    In addition to maxHeight and minHeight, there should be a defaultHeight. When the panel opens up, it should open in defaultHeight. And if maxHeight is bigger than defaultHeight and the user pulls the panel towards top, it should snap to maxHeight. This can be taken even further to make the panel full screen if pulled all the way. What do you think of this feature? It gives the end user much more flexibility and ease of use imho.

    enhancement next version 
    opened by aytunch 10
  • Too much widget rebuild occurring when using PanelBuilder [BETA]

    Too much widget rebuild occurring when using PanelBuilder [BETA]

    Hi @akshathjain

    Just started playing around with the new PanelBuilder (beta) using this code snippet from your example docs:

    // The sliding up panel
    SlidingUpPanel(
          panelBuilder: (ScrollController sc) => _scrollingList(sc),
          body: Center(
            child: Text("This is the Widget behind the sliding panel"),
          ),
    )
    // The scrolling list
    Widget _scrollingList(ScrollController sc) {
        print('scrolling list rebuilt');
        return ListView.builder(
          controller: sc,
          itemCount: 50,
          itemBuilder: (BuildContext context, int i) {
            return Container(
              padding: const EdgeInsets.all(12.0),
              child: Text("$i"),
            );
          },
        );
      }
    
    • I added a print statement print('scrolling list rebuilt');.
    • PanelBuilder (beta) keeps rebuilding the widget when scrolling the list. This need to be fixed.

    Console log output for reference:

    I/flutter ( 9831): scrolling list rebuilt
    I/flutter ( 9831): scrolling list rebuilt
    I/flutter ( 9831): scrolling list rebuilt
    I/flutter ( 9831): scrolling list rebuilt
    I/flutter ( 9831): scrolling list rebuilt
    I/flutter ( 9831): scrolling list rebuilt
    

    NOTE: When adding setState calls inside _scrollingList widget, it causes even more drastic performance issues as the widget gets rebuilt multiple times.

    next version 
    opened by rohansohonee 9
  • Fix crashing at controller methods

    Fix crashing at controller methods

    Fix issue #14.

    Issue: Invoking any controller methods before the panel init causes crashing. It makes it no possible to use BlocBuilder for building the panel.

    Crashing exception:

    ════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
    The following NoSuchMethodError was thrown building BlocBuilder<PanelBloc, PanelState>(dirty, state: _BlocBuilderBaseState<PanelBloc, PanelState>#1d022):
    The method 'call' was called on null.
    Receiver: null
    Tried calling: call()
    
    User-created ancestor of the error-causing widget was: 
      PanelExample file:///Users/oleg.bondar/my/flutter/my/lib/main2.dart:17:56
    When the exception was thrown, this was the stack: 
    #0      Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
    #1      PanelController.hide (package:sliding_up_panel/src/panel.dart:508:5)
    #2      _State.build.<anonymous closure> (package:my/main2.dart:37:17)
    #3      BlocBuilder.build (package:flutter_bloc/src/bloc_builder.dart:88:50)
    #4      _BlocBuilderBaseState.build (package:flutter_bloc/src/bloc_builder.dart:157:48)
    ...
    ════════════════════════════════════════════════════════════════════════════════════════════════════
    

    Code example:

    import 'package:bloc/bloc.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_bloc/flutter_bloc.dart';
    import 'package:sliding_up_panel/sliding_up_panel.dart';
    
    void main() {
      runApp(PanelApp());
    }
    
    class PanelApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
            title: "PanelApp",
            home: Scaffold(
              body: BlocProvider<PanelBloc>(
                  create: (context) => PanelBloc(), child: PanelExample()),
            ));
      }
    }
    
    class PanelExample extends StatefulWidget {
      @override
      State createState() {
        return _State();
      }
    }
    
    class _State extends State<PanelExample> {
      PanelController _pc = PanelController();
    
      @override
      Widget build(BuildContext context) => BlocBuilder<PanelBloc, PanelState>(
            builder: (context, state) {
              var text = "";
              if (state is NoDataForPanel) {
                _pc.hide();
              }
              if (state is WithDataForPanel) {
                _pc.show();
                text = state.data;
              }
    
              return SlidingUpPanel(
                body: Container(
                  child: Center(
                    child: RaisedButton(onPressed: () {
                      // Click to show panel
                      BlocProvider.of<PanelBloc>(context).add(ShowPanel());
                    }),
                  ),
                ),
                panel: Text(text),
                controller: _pc,
              );
            },
          );
    }
    
    // Bloc
    class PanelBloc extends Bloc<PanelEvent, PanelState> {
      @override
      PanelState get initialState => NoDataForPanel();
    
      @override
      Stream<PanelState> mapEventToState(PanelEvent event) async* {
        if (event is ShowPanel) {
          yield WithDataForPanel("Data to show in panel");
        }
      }
    }
    
    // Events
    abstract class PanelEvent {}
    
    class ShowPanel extends PanelEvent {}
    
    // States
    abstract class PanelState {}
    
    class NoDataForPanel extends PanelState {}
    
    class WithDataForPanel extends PanelState {
      final String data;
    
      WithDataForPanel(this.data);
    }
    
    

    Additional dependencies: Bloc Flutter bloc

    opened by bullet-tooth 9
  • body out of panel!

    body out of panel!

    i am having a very weird problem with the panel and that's the body is being displayed outside, like this off5ZZIl1n here is the code

    where I use the panel:

    class HomePage extends StatefulWidget {
      @override
      _HomePageState createState() => _HomePageState();
    }
    
    class _HomePageState extends State<HomePage> {
      final Completer<GoogleMapController> _controller = Completer();
      static const _center = LatLng(45.521563, -122.67433);
      final LatLng _lastMapPosition = _center;
      final _pc = PanelController();
    
      _onMapCreated(GoogleMapController controller) {
        _controller.complete(controller);
      }
    
      // _onCameraMove(CameraPosition position) {
      //     _lastMapPosition = position.target;
      // }
    
      @override
      Widget build(BuildContext context) {
        ScreenUtil.init(context);
        return Scaffold(
          backgroundColor: Colors.black,
          drawer: CustomDrawer(),
          body: Container(
            color: Colors.grey,
            child: Stack(
              children: <Widget>[
                RaisedButton(
                  child: Text('Open Dialog'),
                  onPressed: () => CoolAlert.show(
                    context: context,
                    type: CoolAlertType.info,
                    title: 'No nearby drivers',
                    text: 'Please call for a driver now, 9085095433',
                  ),
                ),
                Positioned(
                  top: 0.08.hp,
                  left: 0.10.wp,
                  child: Container(
                    width: 0.8.wp,
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.only(
                        topLeft: Radius.circular(35),
                        bottomRight: Radius.circular(45),
                        bottomLeft: Radius.circular(35),
                      ),
                      boxShadow: [
                        BoxShadow(
                          color: Colors.black.withOpacity(0.5),
                          spreadRadius: 4,
                          blurRadius: 7,
                          offset: Offset(0, 3),
                        ),
                      ],
                    ),
                    padding: EdgeInsets.symmetric(
                      vertical: 12,
                      horizontal: 10,
                    ),
                    child: Padding(
                      padding: const EdgeInsets.only(left: 12.0),
                      child: Row(
                        children: [
                          Icon(
                            Icons.circle,
                            size: 10,
                            color: appBlue,
                          ),
                          SizedBox(width: 0.02.wp),
                          Text(
                            'Your Taxi has arrived',
                            style: GoogleFonts.hammersmithOne(
                              fontSize: 45.sp,
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
                GoogleMap(
                  // onMapCreated: _onMapCreated,
                  initialCameraPosition: CameraPosition(
                    target: _center,
                    zoom: 11.0,
                  ),
                ),
                SlidingUpPanel(
                  controller: _pc,
                  panel: NavigateHeader(),
                  body: NavigateBody(),
                  // isDraggable: false,
                  color: Colors.transparent,
                  boxShadow: null,
                  minHeight: 0.30.hp,
                ),
              ],
            ),
          ),
        );
      }
    }
    

    and the body code:

    class NavigateBody extends StatelessWidget {
      final _navigationService = NavigatorService.make();
    
      @override
      Widget build(BuildContext context) {
        return SingleChildScrollView(
          child: Column(
            children: <Widget>[
              BottomSheetTile(
                onTap: () => _navigationService.navigateTo(HomeAddressPage.tag),
                leading: Icon(Icons.house),
                title: 'Set Home Address',
              ),
              BottomSheetTile(
                onTap: () => _navigationService.navigateTo(WorkAddressPage.tag),
                leading: Icon(Icons.work),
                title: 'Set Work Address',
              ),
              BottomSheetTile(
                onTap: () => _navigationService.navigateTo(SelectAddressPage.tag),
                leading: Icon(Icons.location_city_rounded),
                title: 'Select from saved places',
              ),
            ],
          ),
        );
      }
    }
    

    BottomSheetTile

    class BottomSheetTile extends StatelessWidget {
      final String title;
      final Widget leading;
      final VoidCallback onTap;
    
      BottomSheetTile({
        Key key,
        this.title,
        this.leading,
        this.onTap,
      }) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return ListTile(
          onTap: onTap,
          leading: leading,
          title: Text(
            title,
            style: GoogleFonts.roboto(
              color: Colors.blue,
              fontSize: 20,
              fontWeight: FontWeight.w700,
            ),
          ),
          trailing: Icon(Icons.arrow_forward_sharp),
        );
      }
    }
    
    opened by hewa-jalal 8
  • PanelController must be attached to a SlidingUpPanel

    PanelController must be attached to a SlidingUpPanel

    Describe the bug in my app I am trying to open/close the panel manually by pressing the header of the panel or any button in the body() but I found this error"

    Log Message The following assertion was thrown while handling a gesture: PanelController must be attached to a SlidingUpPanel 'package:sliding_up_panel/src/panel.dart': Failed assertion: line 629 pos 12: 'isAttached'

    When the exception was thrown, this was the stack: #2 PanelController.open (package:sliding_up_panel/src/panel.dart:629:12) #3 MyHome._body. (package:gym_bar_sales/ui/views/Add/sliding_up_panel_widget.dart:31:21) #4 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:993:19) #5 _InkResponseState.build. (package:flutter/src/material/ink_well.dart:1111:38) #6 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:183:24) ... Handler: "onTap" Recognizer: TapGestureRecognizer#4971a debugOwner: GestureDetector state: possible won arena finalPosition: Offset(656.5, 105.5) finalLocalPosition: Offset(60.5, 19.5) button: 1 sent tap down ═══════════════════════════════════════════════════════

    Expected behavior the panel open or close when calling _pc.open() or .close()

    Smartphone

    • Device: [iPhone 11 Pro Max ]
    • OS: [iOS 14.0]
    • Flutter Version [1.22.0-12.2]
    • sliding_up_panel Version [1.0.2]

    Sample main.dart

    import 'package:flutter/material.dart';
    import 'package:sliding_up_panel/sliding_up_panel.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: "Sliding Up Panel",
          home: Home(),
        );
      }
    }
    
    class Home extends StatelessWidget {
      PanelController _pc = 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(),
              ),
            ],
          ),
        );
      }
    }
    
    opened by omar-hanafy 6
  • Change backdrop closing to use onTapDown rather than onTap

    Change backdrop closing to use onTapDown rather than onTap

    Right now, the GestureDetector for the backdrop uses onTap for detecting when the panel should be closed. Unfortunately this means that downward swipes in the backdrop--a natural user gesture--don't behave as expected, leaving the panel open still.

    By using onTapDown, any gesture, including a swipe and a tap, will effectively close the panel.

    Thanks!

    opened by frmatthew 6
  • MaxHeight to wrap content's height

    MaxHeight to wrap content's height

    Hi there, I have a quick question if there's any wrap panel's content height? I want the panel's height to be dynamic to it's child. I tried to get the height of the panel's child widget then set it to the maxHeight so that when the panel opens, the maxheight will be adjusted but this doesn't work because the widget isn't available yet when the calculation performed.

    The only way of doing this is in the onPanelOpened callback to calculate and adjust the height of the panel. The problem here is that the animation it adjusted the new height doesn't look good. It jump to the new height and fix itself in position. Have any ways to achieve this?

    Thank you. :)

    opened by imchivaa 6
  • Scrollable content as body

    Scrollable content as body

    How can I add something scrollable like a ListView as the body? Currently the closed panel hides the content and disables scrolling on the content. Also a padding beneath the closed panel needs to be added for that. Is such thing possible yet?

    opened by provokateurin 6
  • The Collapsed Widget is still interactive yet invisible when the panel is open.

    The Collapsed Widget is still interactive yet invisible when the panel is open.

    If your collapsed widget has any type of gesture detector you won't be able to interact with the top part of the panel. It should be just wrapped inside a conditional IgnorePointer.

    bug 
    opened by MasiaVittorio 6
  • Tap on panel body as first gesture closes the panel.

    Tap on panel body as first gesture closes the panel.

    I'm using panelBuilder and a SingleChildScrollView as panel body. If I scroll first and then tap nothing happens and works fine. If I first tap on the body the panel closes immediately.

    opened by Bad-Mother-Fucker 5
  • Still maintained ?

    Still maintained ?

    Hello @akshathjain

    I use this package for production, but I see it hasn't been updated in a long time, is it still being maintained?, Please give me a sign bro.

    Thanks

    opened by devappbox 6
  • The area at the top of the sliding up panel is not clickable

    The area at the top of the sliding up panel is not clickable

    Describe the bug As you can see from the screenshot, there are 2 links (Explore and Shop). However, the top area of the panel has some kind of an invisible container that covers most of these 2 links which make it very hard for the user to tap on the links.

    When some padding is added to the top, the links are pushed down and easier to tap on. However, this looks rather ugly.

    Is it possible to remove this unclickable area at the top? I think having links at the top of the panel is quite a common use case. Thank you!

    Expected behavior Sliding up panel should allow links or buttons at the top.

    Screenshots Hard to click on Explore and Shop links image

    Ugly workaround image

    Smartphone (please complete the following information):

    • Device: iPhone 13 Pro (simulator)
    • OS: iOS15.5
    • Flutter Version: 3.0.5
    • sliding_up_panel Version: 2.0.0+1
    opened by anhnk 2
  • Firebase Crashlytics _SlidingUpPanelState._onGestureSlide

    Firebase Crashlytics _SlidingUpPanelState._onGestureSlide

    Describe the bug Firebase crashlytics reported issue and causing a lot of events being reported. Around 22K events are being reported on a production app by 2.7K users out of 5.5K users.

    stacktrace

    Non-fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: Null check operator used on a null value. Error thrown Instance of 'ErrorDescription'.
           at AnimationController.stop(animation_controller.dart:778)
           at AnimationController.value=(animation_controller.dart:363)
           at _SlidingUpPanelState._onGestureSlide(panel.dart:473)
           at _SlidingUpPanelState._gestureHandler.<fn>(panel.dart:461)
           at RenderPointerListener.handleEvent(proxy_box.dart:2914)
           at GestureBinding.dispatchEvent(binding.dart:425)
           at RendererBinding.dispatchEvent(binding.dart:329)
           at GestureBinding._handlePointerEventImmediately(binding.dart:380)
           at GestureBinding.handlePointerEvent(binding.dart:344)
           at GestureBinding._flushPointerEventQueue(binding.dart:302)
           at GestureBinding._handlePointerDataPacket(binding.dart:285)
    

    Screenshots Screenshot 2022-09-06 at 11 24 31 AM

    Additional context this is the crashlytics logs Screenshot 2022-09-06 at 11 26 25 AM

    Smartphone (please complete the following information):

    • Device: Galaxy A03s (12%) , Galaxy A12 (25%), Galaxy A02 (2%), Other (61%)
    • OS: Android 12 (37%), Android 11 (35%), Android 10 (20%), Android 9 (6%), other (2%)
    • Flutter Version: 3.0.0
    • sliding_up_panel Version 2.0.0+1
    opened by nayefmazen 0
  • RefreshIndicator doesn't work with panelBuilder

    RefreshIndicator doesn't work with panelBuilder

    Describe the bug When using a RefreshIndicator inside the panelBuilder, you can't pull down to use the RefreshIndicator. I have tested that the code I'm using works by itself as expected.

    To Reproduce Steps to reproduce the behavior:

    • Place a RefreshIndicator inside the panelBuilder.
    • Use a ListView Builder to make it scrollable.

    Expected behavior When the panel is all the way down and you pull down, the RefreshIndicator should do its thing.

    Smartphone (please complete the following information):

    • Device: iOS Simulator
    • OS: iOS 15.2
    • Flutter Version: 3.0.5
    • sliding_up_panel Version: 2.0.0

    Sample main.dart Please provide a sample main.dart that reproduces this issue. The code provided here should be able to be run on its own without any external dependencies.

    import 'package:flutter/material.dart';
    import 'package:sliding_up_panel/sliding_up_panel.dart';
    
    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(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const WithSlidingPanel(), //It works without using SlidingPanel, but not with.
        );
      }
    }
    
    class WithSlidingPanel extends StatelessWidget {
      const WithSlidingPanel({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          backgroundColor: Theme.of(context).colorScheme.background,
          body: SlidingUpPanel(
            minHeight: MediaQuery.of(context).size.height * 0.3,
            maxHeight: MediaQuery.of(context).size.height * 0.9,
            panelBuilder: recordingList,
            body: body(context),
          ),
        );
      }
    
      Widget body(BuildContext context) {
        return const Center(
          child: Text("I'm the body!"),
        );
      }
    
      Widget recordingList(ScrollController scrollController) {
        return RefreshIndicator(
          onRefresh: () async {},
          child: ListView.builder(
            controller: scrollController,
            itemCount: 10,
            itemBuilder: (context, index) {
              return Container(
                color: Colors.blue,
                height: 100,
                child: Center(
                  child: Text("I'm widget number $index"),
                ),
              );
            },
          ),
        );
      }
    }
    
    class WithoutSlidingPanel extends StatelessWidget {
      const WithoutSlidingPanel({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: RefreshIndicator(
            onRefresh: () async {},
            child: ListView.builder(
              itemCount: 10,
              itemBuilder: (context, index) {
                return Container(
                  color: Colors.blue,
                  height: 100,
                  child: Center(
                    child: Text("I'm widget number $index"),
                  ),
                );
              },
            ),
          ),
        );
      }
    }
    
    
    opened by JoakimMellonn 0
  • Fix gestures in collapsed not working

    Fix gestures in collapsed not working

    Fixes https://github.com/akshathjain/sliding_up_panel/issues/180 https://github.com/akshathjain/sliding_up_panel/issues/212 https://github.com/akshathjain/sliding_up_panel/issues/228 https://github.com/akshathjain/sliding_up_panel/issues/19

    Related: https://github.com/akshathjain/sliding_up_panel/pull/302 and others..

    opened by rootd 0
Releases(v2.0.0+1)
  • v2.0.0+1(Apr 27, 2021)

  • v2.0.0(Apr 27, 2021)

  • v1.0.2(Apr 13, 2020)

    Features

    • Addressed issues #71, #103 - Added an optional header widget that floats above the panel and attaches to the top
    • Added an optional footer widget that floats above the panel and attaches to the bottom

    Documentation

    • Updated documentation to reflect new features and fixes
    Source code(tar.gz)
    Source code(zip)
  • v1.0.1(Apr 2, 2020)

    Fixes

    • Addressed issue #94: Too much widget rebuild occurring when the user slides the panel. This fix results in huge performance benefits when using the panelChild and panelBuilder properties
    • Addressed issues #102, #111: Fixed issue where tapping on the panel closes it (when using the panelBuilder)
    • Addressed issues #24, #70, #108, #121: Changed backdropTapClosesPanel to use onTap and onVerticalDragEnd so swipes on the backdrop cause the panel to close

    Features

    • Addressed issue #107: Added duration and curve properties to the PanelController's animatePanelToPosition method
    • Addressed issues #12,#77,#86,#100: Added a snapPoint property to allow the panel to snap to a position midway during its slide

    Documentation

    • Updated documentation to reflect new features and fixes
    • Updated copyright year in the LICENSE
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Jan 26, 2020)

    Fixes

    • Addressed issue #69: Used a FadeTransition to handle opacity changes (as per Flutter documentation)
    • Cleaned up PanelController code to make maintenance easier
    • Added clearer assert statements and messages to indicate why calling PanelController methods would fail before attaching the PanelController.

    Features

    • Addressed issues #17, #55, #60: Added the ability to link / nested the scroll position of the panel content with the position of the panel (i.e. infinite scrolling).
    • Added the panelBuilder property that's required to implement the nested scrolling as described above.
    • Added an isAttached property to the PanelController to indicate whether or not the PanelController is attached to an instance of the SlidingUpPanel

    Breaking Changes

    The following PanelController methods now return Future<void> instead of void:

    • close()
    • open()
    • hide()
    • show()
    • animatePanelToPosition(double value)

    The following PanelController methods have changed to Dart properties to better reflect Dart language conventions:

    • setPanelPosition() -> panelPosition [as a setter]
    • getPanelPosition() -> panelPosition [as a getter]
    • isPanelAnimating() -> isPanelAnimating
    • isPanelOpen() -> isPanelOpen
    • isPanelClosed() -> isPanelClosed
    • isPanelShown() -> isPanelShown

    For example, here's how you would have previously used setPanelPosition() and getPanelPosition() vs. how you would now use the panelPosition property:

    // OLD, no longer supported
    print(pc.getPanelPosition()); // print a value between 0.0 and 1.0
    pc.setPanelPosition(0.5);     // sets the panelPosition to 0.5
    
    // NEW
    print(pc.panelPosition); // print a value between 0.0 and 1.0
    pc.panelPosition = 0.5;  // sets the panelPosition to 0.5
    

    And here's how you would have previously called isPanelAnimating() vs. how you would now call isPanelAnimating.

    panelController.isPanelAnimating(); // OLD, no longer supported
    
    panelController.isPanelAnimating; // NEW
    

    Documentation

    • Updated the documentation to reflect changes
    • Updated example to use nested scrolling
    Source code(tar.gz)
    Source code(zip)
  • v0.3.6(Sep 25, 2019)

    Fixes

    • Fixed issues #54, #59 where panel listeners would be called before UI was rendered (related to defaultPanelState)

    Documentation

    • Updated the documentation to reflect fixes
    Source code(tar.gz)
    Source code(zip)
  • 0.3.5(Aug 31, 2019)

    Features

    • Added the defaultPanelState property that changes whether the panel is either open or closed by default (PanelState.OPEN or PanelState.CLOSED)

    Documentation

    • Updated the documentation to reflect new features
    Source code(tar.gz)
    Source code(zip)
  • v0.3.4(Apr 16, 2019)

    Features

    • Added slideDirection property that changes how the panel slides open (either up or down)

    Documentation

    • Updated the documentation to reflect new features
    Source code(tar.gz)
    Source code(zip)
  • v0.3.3(Apr 7, 2019)

    Features

    • Added isDraggable property that allows/prevents dragging of the panel

    Documentation

    • Updated the documentation to reflect new features
    Source code(tar.gz)
    Source code(zip)
  • v0.3.2(Apr 5, 2019)

  • v0.3.1(Apr 5, 2019)

    Features

    • Configuration options to SlidingUpPanel
      • parallaxEnabled
      • parallaxOffset

    Documentation

    • Created a new example app (Maps)
    • Updated documentation to reflect new features
    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(Apr 2, 2019)

    Features

    • Added ability to close the panel when the backdrop is tapped

    • Added callbacks to the SlidingUpPanel

      • onPanelSlide
      • onPanelOpened
      • onPanelClosed
    • Added methods to the PanelController

      • setPanelPosition
      • animatePanelToPosition
      • getPanelPosition
      • isPanelAnimating
      • isPanelOpen
      • isPanelClosed
      • isPanelShown

    Bug Fixes

    • Fixed issue where the collapsed widget would accept touch events even when invisible (i.e. even when the panel was fully open)

    Documentation

    • Updated documentation to reflect new features
    • Added clarification on PanelController lifecycle
    • Added an explanation about nesting the Scaffold when displaying a backdrop
    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Apr 1, 2019)

    Added the backdrop feature:

    • Body darkens as the panel opens
    • The backdrop color is customizable
    • The backdrop opacity is also customizable
    • Off by default

    Other changes:

    • Removed the README from the example app (pub will display the code on the website now)
    • Specified Dart as the language in the README code snippets
    Source code(tar.gz)
    Source code(zip)
  • v0.1.2(Mar 31, 2019)

  • v0.1.1(Mar 31, 2019)

  • v0.1.0(Mar 31, 2019)

    Overview

    This is the initial release of the sliding_up_panel package. This includes features such as

    • A sliding up panel that responds to user gestures
    • Customizing the look and feel of the sliding panel
    • Manually controlling the sliding panel via the PanelController
    Source code(tar.gz)
    Source code(zip)
A Flutter package for easily implementing Material Design navigation transitions.

Morpheus A Flutter package for easily implementing Material Design navigation transitions. Examples Parent-child transition You can use MorpheusPageRo

Sander R. D. Larsen 186 Jan 7, 2023
A Flutter library that makes animation easer. It allows for separation of animation setup from the User Interface.

animator This library is an animation library for Flutter that: makes animation as simple as the simplest widget in Flutter with the help of Animator

MELLATI Fatah 225 Dec 22, 2022
A custom Flutter value slider that makes a wave effect when dragged.

A Flutter slider that makes a wave effect when dragged. Does a little bounce when dropped. Demo Getting Started To use this plugin, add wave_slider as

Gordon Hayes 33 Dec 21, 2022
A Flutter widget that easily adds the flipping animation to any widget

flip_card A component that provides a flip card animation. It could be used for hiding and showing details of a product. How to use import 'package:fl

Bruno Jurković 314 Dec 31, 2022
A widget that allow user resize the widget with drag

Flutter-Resizable-Widget A widget that allow user resize the widget with drag Note: this widget uses Getx Example bandicam.2021-11-11.12-34-41-056.mp4

MohammadAminZamani.afshar 22 Dec 13, 2022
Circular Reveal Animation as Flutter widget!

Circular Reveal Animation Circular Reveal Animation as Flutter widget! Inspired by Android's ViewAnimationUtils.createCircularReveal(...). Статья с оп

Alexander Zhdanov 48 Aug 15, 2022
A Flutter Package providing Avatar Glow Widget

Avatar Glow This Flutter package provides a Avatar Glow Widget with cool background glowing animation. Live Demo: https://apgapg.github.io/avatar_glow

Ayush P Gupta 250 Dec 22, 2022
✨A clean and lightweight loading/toast widget for Flutter, easy to use without context, support iOS、Android and Web

Flutter EasyLoading English | 简体中文 Live Preview ?? https://nslog11.github.io/flutter_easyloading Installing Add this to your package's pubspec.yaml fi

nslog11 1k Jan 9, 2023
A beautiful animated flutter widget package library. The tab bar will attempt to use your current theme out of the box, however you may want to theme it.

Motion Tab Bar A beautiful animated widget for your Flutter apps Preview: | | Getting Started Add the plugin: dependencies: motion_tab_bar: ^0.1.5 B

Rezaul Islam 237 Nov 15, 2022
a widget provided to the flutter scroll component drop-down refresh and pull up load.

flutter_pulltorefresh Intro a widget provided to the flutter scroll component drop-down refresh and pull up load.support android and ios. If you are C

Jpeng 2.5k Jan 5, 2023
Highly customizable, feature-packed calendar widget for Flutter

TableCalendar Highly customizable, feature-packed calendar widget for Flutter. TableCalendar with custom styles TableCalendar with custom builders Fea

Aleksander Woźniak 1.5k Jan 7, 2023
Flutter 3D Flip Animation Widget

flutter_flip_view This is a flutter Widget base on pure Dart code that provides 3D flip card visuals. Usage add package in your pubspec.yaml dependenc

WosLovesLife 57 Dec 30, 2022
A simple toggle switch widget for Flutter.

Toggle Switch A simple toggle switch widget. It can be fully customized with desired icons, width, colors, text, corner radius, animation etc. It also

Pramod Joshi 84 Nov 20, 2022
Base Flutter widget which triggers rebuild only of props changed

pure_widget Base widget which triggers rebuild only if props changed Installation pubspec.yaml: dependencies: pure_widget: ^1.0.0 Example import 'da

Andrei Lesnitsky 9 Dec 12, 2022
A Stepper Widget in Flutter using GetX

Stepper Flutter GetX Donate If you found this project helpful or you learned something from the source code and want to thank me, consider buying me a

Ripples Code 0 Nov 27, 2021
A Flutter dropdown widget.

Flutter Dropdown_Below A Flutter Dropdown library which is customize flutter dropdownbutton widget. Options options description type required itemWidt

Denny Hong 27 Sep 7, 2022
Flutter's core Dropdown Button widget with steady dropdown menu and many options you can customize to your needs.

Flutter DropdownButton2 Intro Flutter's core Dropdown Button widget with steady dropdown menu and many options you can customize to your needs. Featur

AHMED ELSAYED 125 Jan 4, 2023
Flutter widget that automatically resizes text to fit perfectly within its bounds.

ONLY FOR FLUTTER WEB Flutter widget that automatically resizes text to fit perfectly within its bounds. Show some ❤️ and star the repo to support the

Rebar Ahmad 4 Jan 6, 2022
Flutter fluid slider - A fluid design slider that works just like the Slider material widget

Fluid Slider for Flutter Inspired by a dribbble by Virgil Pana. A fluid design s

Jay Raj 2 Feb 18, 2022