Giter Site home page Giter Site logo

akshathjain / sliding_up_panel Goto Github PK

View Code? Open in Web Editor NEW
1.4K 20.0 378.0 136.11 MB

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

Home Page: https://pub.dartlang.org/packages/sliding_up_panel

License: Other

Objective-C 0.09% Dart 92.86% Ruby 5.02% Python 0.80% Kotlin 0.29% Swift 0.94%
dart flutter plugin

sliding_up_panel's Introduction

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

sliding_up_panel's People

Contributors

akshathjain avatar s0nerik avatar uintdev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sliding_up_panel's Issues

Dark brightness mode in ThemeData vanishes all widgets

Hi,
The current version has an issue with brightness mode.
steps to reproduce

  1. add a dark brightness in your example

return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'SlidingUpPanel Example',
theme: ThemeData(primarySwatch: Colors.blue, brightness: Brightness.dark),
home: HomePage(),
);

  1. run and get the result like this
    https://uppic.cc/d/5v25

all the text is gone. maybe it does not respect the dark mode.

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!

PanelController should have a listener for when the panel slides

The PanelController should have a listener that subscribes to the animation controller and is called every time the animation changes (i.e. the panel slides open/closed). This can be useful for adding custom animations that are based on the panel position. For example:

PanelController pc = new PanelController();

pc.addOnPanelSlideListener((double position){
  print(position); //0.0 to 1.0 where 0.0 is full collapsed and 1.0 is fully open
});

close panel when i press on back

how can i close panel when i press on back button on phone?

this code don't work

class _LoginForm extends State<LoginForm> with SingleTickerProviderStateMixin {
  PanelController _pc = new PanelController();

...

return WillPopScope(
  onWillPop: () {
    if(_pc.isPanelShown()){
      _pc.hide();
    }
  },
  child: Scaffold(

Close panel when keyboard is open

It would be useful to add the option for close automatically the panel when the keyboard is open.
As show in the screenshot the panel is above the keyboard. When the panel is fully opened and a TextField is focused the panel obscure all the view.

not-fully opened
screenshot

fully opened
screenshot 2

tutorial

Some tutorial or artical on medium on this would be amazing!:)

Full Height with Scaffold, no safe area

Hello, I'm trying to extend the Panel to "full height" when it is open

SlidingUpPanel(
  minHeight: UiPlayerShrinked._kPlayerBodyHeight,
  maxHeight: MediaQuery.of(context).size.height,
  controller: _pc,
  onPanelOpened: () => updateIsPlayerExtendedShowing(true),
  onPanelClosed: () => updateIsPlayerExtendedShowing(false),
  collapsed: buildShrinkedPlayer(playingBeat, context),
  panel: Scaffold(
    body: Text('Scaffold'),
  ),

Although there are a couple of problems:

First is this error:

flutter: #11     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout 
package:flutter/…/rendering/proxy_box.dart:105
flutter: #12     RenderObject.layout 
package:flutter/…/rendering/object.dart:1644
flutter: #13     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout 
package:flutter/…/rendering/proxy_box.dart:105
flutter: #14     RenderObject.layout 
package:flutter/…/rendering/object.dart:1644
flutter: #15     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout 
package:flutter/…/rendering/proxy_box.dart:105
flutter: #16     RenderObject.layout 
package:flutter/…/rendering/object.dart:1644
flutter: #17     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout 
package:flutter/…/rendering/proxy_box.dart:105
flutter: #18     RenderObject.layout 
package:flutter/…/rendering/object.dart:1644
flutter: #19     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout 
package:flutter/…/rendering/proxy_box.dart:105
flutter: #20     RenderObject.layout 
package:flutter/…/rendering/object.dart:1644
flutter: #21     RenderConstrainedOverflowBox.performLayout 
package:flutter/…/rendering/shifted_box.dart:571
flutter: #22     RenderObject._layoutWithoutResize 
package:flutter/…/rendering/object.dart:1519
flutter: #23     PipelineOwner.flushLayout 
package:flutter/…/rendering/object.dart:766
flutter: #24     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding.drawFrame 
package:flutter/…/rendering/binding.dart:347
flutter: #25     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.drawFrame 
package:flutter/…/widgets/binding.dart:701
flutter: #26     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding._handlePersistentFrameCallback 
package:flutter/…/rendering/binding.dart:286
flutter: #27     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback 
package:flutter/…/scheduler/binding.dart:1012
flutter: #28     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame 
package:flutter/…/scheduler/binding.dart:952
flutter: #29     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._handleDrawFrame 
package:flutter/…/scheduler/binding.dart:864
flutter: #33     _invoke  (dart:ui/hooks.dart:219:10)
flutter: #34     _drawFrame  (dart:ui/hooks.dart:178:3)
flutter: (elided 5 frames from class _AssertionError and package dart:async)
flutter:
flutter: The following RenderObject was being processed when the exception was fired:
flutter:   RenderCustomMultiChildLayoutBox#09649 relayoutBoundary=up8 NEEDS-LAYOUT NEEDS-PAINT
flutter:   creator: CustomMultiChildLayout ← AnimatedBuilder ← DefaultTextStyle ← AnimatedDefaultTextStyle ←
flutter:   _InkFeatures-[GlobalKey#ad7ea ink renderer] ← NotificationListener<LayoutChangedNotification> ←
flutter:   PhysicalModel ← AnimatedPhysicalModel ← Material ← PrimaryScrollController ← _ScaffoldScope ←
flutter:   Scaffold ← ⋯
flutter:   parentData: <none> (can use size)
flutter:   constraints: BoxConstraints(0.0<=w<=414.0, h=896.0)
flutter:   size: Size(414.0, 896.0)
flutter: This RenderObject had the following descendants (showing up to depth 5):
flutter:   _RenderLayoutBuilder#0aed1 relayoutBoundary=up9
flutter:     _RenderScrollSemantics#2b11b relayoutBoundary=up10
flutter:       RenderPointerListener#b3ac8 relayoutBoundary=up11
flutter:         RenderSemanticsGestureHandler#4a540 relayoutBoundary=up12
flutter:           RenderPointerListener#d0ada relayoutBoundary=up13
flutter:   RenderConstrainedBox#adef0 relayoutBoundary=up9
flutter:     RenderSemanticsAnnotations#3a36e relayoutBoundary=up10
flutter:       RenderAnnotatedRegion<SystemUiOverlayStyle>#61585 relayoutBoundary=up11
flutter:         RenderPhysicalModel#e90d0 relayoutBoundary=up12
flutter:           _RenderInkFeatures#4d6ad relayoutBoundary=up13
flutter:   RenderFlex#a74c8 relayoutBoundary=up9 NEEDS-PAINT
flutter:     RenderStack#834eb relayoutBoundary=up10 NEEDS-PAINT
flutter:       RenderLimitedBox#3e5ec relayoutBoundary=up11
flutter:         RenderConstrainedBox#de0f0 relayoutBoundary=up12
flutter:       RenderLimitedBox#78b88 relayoutBoundary=up11
flutter:         RenderConstrainedBox#e7caa relayoutBoundary=up12
flutter:       RenderSemanticsGestureHandler#5ff96 relayoutBoundary=up11 NEEDS-PAINT
flutter:         RenderPointerListener#86019 relayoutBoundary=up12 NEEDS-PAINT
flutter:           RenderConstrainedBox#54ac0 relayoutBoundary=up13 NEEDS-PAINT
flutter:     RenderDecoratedBox#24077 relayoutBoundary=up10
flutter:       RenderConstrainedBox#227f5 relayoutBoundary=up11
flutter:         RenderPadding#c4b38 relayoutBoundary=up12
flutter:           RenderFlex#64816 relayoutBoundary=up13
flutter:   RenderStack#02564 relayoutBoundary=up9
flutter:     RenderTransform#35b38 relayoutBoundary=up10
flutter:       RenderTransform#c3d02 relayoutBoundary=up11
flutter: ════════════════════════════════════════════════════════════════════════════════════════════════════
flutter: Another exception was thrown: 'package:flutter/src/material/scaffold.dart': Failed assertion: line 423 pos 16: 'bodyMaxHeight <= math.max(0.0, looseConstraints.maxHeight - contentTop)': is not true.
flutter: Another exception was thrown: A RenderFlex overflowed by 10 pixels on the bottom.
flutter: Another exception was thrown: 'package:flutter/src/material/scaffold.dart': Failed assertion: line 423 pos 16: 'bodyMaxHeight <= math.max(0.0, looseConstraints.maxHeight - contentTop)': is not true.
flutter: Another exception was thrown: 'package:flutter/src/material/scaffold.dart': Failed assertion: line 423 pos 16: 'bodyMaxHeight <= math.max(0.0, looseConstraints.maxHeight - contentTop)': is not true.
flutter: Another exception was thrown: 'package:flutter/src/material/scaffold.dart': Failed assertion: line 423 pos 16: 'bodyMaxHeight <= math.max(0.0, looseConstraints.maxHeight - contentTop)': is not true.
flutter: Another exception was thrown: 'package:flutter/src/material/scaffold.dart': Failed assertion: line 423 pos 16: 'bodyMaxHeight <= math.max(0.0, looseConstraints.maxHeight - contentTop)': is not true.
flutter: Another exception was thrown: 'package:flutter/src/material/scaffold.dart': Failed assertion: line 423 pos 16: 'bodyMaxHeight <= math.max(0.0, looseConstraints.maxHeight - contentTop)': is not true.
flutter: Another exception was thrown: 'package:flutter/src/material/scaffold.dart': Failed assertion: line 423 pos 16: 'bodyMaxHeight <= math.max(0.0, looseConstraints.maxHeight - contentTop)': is not true.
flutter: Another exception was thrown: Updated layout information required for _RenderLayoutBuilder#0aed1 relayoutBoundary=up9 NEEDS-LAYOUT to calculate semantics.
	[C61.1 903ABA02-99A7-41A4-B22F-87E88066A736 192.168.1.117:62932<->18.194.48.246:443]
	Connected Path: satisfied (Path is satisfied), interface: en0
	Duration: 30.893s, DNS @0.000s took 0.001s, TCP @0.003s took 0.031s, TLS took 0.069s
	bytes in/out: 5047/1673, packets in/out: 8/6, rtt: 0.031s, retransmitted packets: 0, out-of-order packets: 0

The second issue is that there is no "safe area". I'm actually trying to emulate a "view" when the panel is open, with AppBar and Body but I can't achieve that because the content is pushed to the very edges

Close/Open panel on tap instead of dragging?

Thanks so much for this, very helpful!
Is there a way to open the panel on tap instead of dragging it? I have a scroll view inside it so dragging causes only the view inside to scroll and I can't open the panel itself.
I know I can open it with a button and call _pc.open(), but ideally I'd want to open on backdrop tap, so any area of the header will open it. And I tried to close it with backdropTapClosesPanel: true but it won't work somehow.

set max height of preview

is any solution about setting max height of preview panel? i mean when i run application of show scrren i want to have custom height of panel

[Feature Request] AnimatedContainer in place of Container?

Hi! Really love the package! What are your thoughts on making the container here an AnimatedContainer?

I have the use case where my panel can hava data in it or be empty (it's holding a sport player's information). The user can click on a player in main UI list to fetch the data and on load I wanted the panel to animate up to a minimum height of 60 (whereas it's empty value is 40). Using setState and animated container, it's as simple as changing the minHeight property on the SlidingUpPanel:

minHeight: playerSummary?.player == null ? 40 : 60,

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?

Adding Opacity

What about adding features to adjust opacity? I think that will help people who want to use gradient background

Panels elements not showing properly

This is the
`Dart
import 'package:flutter/material.dart';
import 'package:sliding_up_panel/sliding_up_panel.dart';

class BottomSheet extends StatefulWidget {
@OverRide
_BottomSheetState createState() => _BottomSheetState();
}

class _BottomSheetState extends State {
final double _initFabHeight = 120.0;
double _fabHeight;
double _panelHeightOpen = 575.0;
double _panelHeightClosed = 95.0;

@OverRide
void initState() {
super.initState();

_fabHeight = _initFabHeight;

}

@OverRide
Widget build(BuildContext context) {
return Material(
child: Stack(
alignment: Alignment.topCenter,
children: [
SlidingUpPanel(
maxHeight: _panelHeightOpen,
minHeight: _panelHeightClosed,
parallaxEnabled: true,
parallaxOffset: .5,
body: _body(),
panel: _panel(),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(18.0),
topRight: Radius.circular(18.0)),
onPanelSlide: (double pos) => setState(() {
_fabHeight = pos * (_panelHeightOpen - _panelHeightClosed) +
_initFabHeight;
}),
),

      // the fab
      Positioned(
        right: 20.0,
        bottom: _fabHeight,
        child: FloatingActionButton(
          child: Icon(
            Icons.gps_fixed,
            color: Theme.of(context).primaryColor,
          ),
          onPressed: () {},
          backgroundColor: Colors.white,
        ),
      ),

      //the SlidingUpPanel Titel
      Positioned(
        top: 42.0,
        child: Container(
          padding: const EdgeInsets.fromLTRB(24.0, 18.0, 24.0, 18.0),
          child: Text(
            "SlidingUpPanel Example",
            style: TextStyle(fontWeight: FontWeight.w500),
          ),
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.circular(24.0),
            boxShadow: [
              BoxShadow(
                  color: Color.fromRGBO(0, 0, 0, .25), blurRadius: 16.0)
            ],
          ),
        ),
      ),
    ],
  ),
);

}

Widget _panel() {
return Text("hahaha");
}

Widget _body() {
return SizedBox.expand(
child: Text("lalals"),
);
}
}
`

Screenshot

minSnapDistance for hide

Right now the y position user needs to bring the panel down for it to disappear is fixed(or maybe a fraction of the maxHeight). Developer should be able to set this according to his/her own needs imho.

Example with Provider for PanelController State Management

So, currently i'm use this plugin and I need to manage the controller from other class, so I'm sharing this public example for anyone who wants to use https://github.com/hectorAguero/slidingpanelexample

Currently I'm works with some similar in a app, but after call a PageRoute(LoginPage to HomePage), I have problems with the controller inside the model class , I don't put that code in the example because I dont have more time now, so all the example works.

The code, doesn't have comments, sorry for that.

Any comment is welcomed

GIF

panel does not dismiss when backdropEnabled: true

When the user presses anywhere except the panel, the panel should hide. But right now nothing happens.

Also, the backdrop overlay only covers the body of the Scaffold. BottomNavigationBar and AppBar are not greyed out.

Set default state to open?

Hi, how can we set the default pannel to be opened;

I use this Widget as my Home page which i need to open this Pannel as default.

So how can we set it?

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.

Add a parallax effect as the panel opens

Add an option that allows the user to configure whether or not there's a parallax effect as the panel is opened. Essentially, this means that as the panel opens, the body slides up as well.

The parallax effect should be configurable with a parameter (such as parallaxOffset) that takes in a double ranging from 0.0 to 1.0 where 0.0 indicates no parallax and 1.0 indicates that the body should be offset by the same amount as the panel's offset from its collapsed state (i.e. a scrolling effect).

Allow to add listeners to a PanelController

For the onPanelSlide , onPanelClosed and onPanelOpened.

For example:

PanelController pc = PanelController();
pc.addOnPanelSlideListener((double position){
  print(position);
});

In release mode weird first few frames flicker on iOS (more obvious on old devices)

As in other similar libraries, this one has that issue, that the size is defined by MediaQuery.of(context).size.width and on the very beggining the issue that may happen is that there is no width defined, or it's wrong. And the process of calculating this value differs in release and debug modes. Issue also reproducable with the example provided. It is obvious on iPhone 5s and pretty noticable on iPhone 6 and family.

different layout on directions

when i change slideDirection to SlideDirection.DOWN or SlideDirection.DOWN i have different layout on screen

http://s6.uplod.ir/i/00953/sz9fo2k942ih.png

http://s6.uplod.ir/i/00953/cf5v1l6xalbp.png

SlidingUpPanel(
  slideDirection:SlideDirection.DOWN,
  maxHeight: MediaQuery.of(context).size.height / 2,
  renderPanelSheet: false,
  backdropEnabled: true,
  boxShadow: [
    BoxShadow(color: Colors.black, blurRadius: 2),
  ],
  panel: Container(
    decoration: BoxDecoration(
      color: Colors.blueGrey,
      borderRadius: BorderRadius.all(Radius.circular(10.0)),
    ),
    margin: const EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 0.0),
    child: Center(
      child: TextField(

      )
    ),
  ),
  collapsed: Container(
    decoration: BoxDecoration(
        color: Colors.white,
        /*borderRadius: BorderRadius.only(
            bottomLeft: Radius.circular(10.0),
            bottomRight: Radius.circular(10.0)),*/
        boxShadow: [
          BoxShadow(
            blurRadius: 20.0,
            color: Colors.grey,
          ),
        ]),
    margin: const EdgeInsets.all(10.0),
    child: Center(
      child: Text("This is the SlidingUpPanel when open"),
    ),
  ),
)

Textfield is overlapped by keyboard (SlidingUpPanel -> panel -> CustomScrollView -> SliverStickyHeader -> TextField)

Code as follow:

return Material(
      child: Scaffold(
        body: Stack(
          alignment: Alignment.topCenter,
          children: <Widget>[
            SlidingUpPanel(
              isDraggable: false,
              color: Colors.cyan,
              controller: _pc,
              maxHeight: MediaQuery.of(context).size.height * 0.87,
              minHeight: MediaQuery.of(context).size.height * 0.7,
              parallaxEnabled: true,
              parallaxOffset: .5,
              body: _body(),
              panel: _panel(),
              borderRadius: BorderRadius.only(
                topLeft: Radius.circular(18.0),
                topRight: Radius.circular(18.0),
              ),
            ),
            Align(
              alignment: Alignment.bottomCenter,
              child: _getCheckoutLayer(),
            ),
          ],
        ),
      ),
    );
  Widget _panel() {
    return Container(
      margin: const EdgeInsets.only(top: 18.0),
      color: Colors.cyan,
      child: NotificationListener<ScrollNotification>(
        onNotification: (scrollNotification) {
          if (scrollNotification is ScrollStartNotification) {
          } else if (scrollNotification is ScrollUpdateNotification) {
            if (scrollNotification.metrics.pixels > _currentPosition) {
              if (_pc.isPanelClosed()) {
                _pc.open();
                setState(() {
                  firstStateEnabled = false;
                });
              }
            }
          } else if (scrollNotification is ScrollEndNotification) {
            if (scrollNotification.metrics.pixels == 0) {
              if (_pc.isPanelOpen()) {
                _pc.close();
                setState(() {
                  firstStateEnabled = true;
                });
              }
            }
          }
          _currentPosition = scrollNotification.metrics.pixels;
          return true;
        },
        child: CustomScrollView(
          physics: ClampingScrollPhysics(),
          slivers: [
            _itemAmount(),
            _items(1),
            _items(2),
            _items(3),
            _items(4),
            _items(5),
            _items(6),
            _itemRemark(),
            _itemBottom(),
          ],
        ),
      ),
    );
  }
  Widget _itemRemark() {
    return SliverStickyHeader(
      header: Container(
        color: Colors.cyan,
        height: 60.0,
        padding: EdgeInsets.only(
          left: 16.0,
          top: 20.0,
          bottom: 10.0,
        ),
        alignment: Alignment.centerLeft,
        child: Text(
          '備註',
          style: const TextStyle(
            color: Colors.white,
            fontSize: 22,
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
      sliver: SliverList(
        delegate: SliverChildBuilderDelegate(
          (context, i) {
            return Container(
              padding: EdgeInsets.only(
                left: 15,
                right: 15,
              ),
              child: Container(
                padding: const EdgeInsets.all(8.0),
                decoration: BoxDecoration(
                    border: Border.all(color: Colors.white),
                    borderRadius: BorderRadius.circular(12.0)),
                child: TextField(
                  textInputAction: TextInputAction.done,
                  maxLines: 5,
                  decoration: InputDecoration.collapsed(hintText: ''),
                  style: TextStyle(color: Colors.white),
                ),
              ),
            );
          },
          childCount: 1,
        ),
      ),
    );
  }

Body is covered by collapsed slide up panel

I am using a ListView as body and it is a list of items. However when the panel is collapsed the body is not above the panel. The last item in the ListView is covered by the collapsed panel. ��

How can I shift it up so the ListView is above the collapsed panel, as to show the last item?

Borders will not round properly

Hi,

I am unable to get the borders to round correctly on my application. Instead, it creates a colour that matches my background colour to fill the corners with.

Sliding up panel moves up when keyboard appears

I have a textfield inside the panel, upon focusing on it the keyboard appears and the whole sliding panel gets pushed up. How do I make it stay at current position, or perhaps only move up a bit.

Screenshot 2019-06-20 at 8 41 21 PM

Screenshot 2019-06-20 at 8 41 45 PM

Body going off screen

I'm running a Sliding Up Panel as the body of a scaffold, with its body consisting of a column surrounded by some padding, but the content (on smaller devices) goes off the screen. If I take the Sliding Up Panel out and have the column as the body of the scaffold it works just fine fitting to the constraints of the screen.

(I've made the collapsed panel very small, to view the content behind it)
1
2

Not sure if I'm implementing this wrong / it's intended behaviour or a bug.

return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.blueGrey[800],
        title: Text('Time Since Last'),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.settings),
            onPressed: () {
              Navigator.pushNamed(context, CategoryEdit.id, arguments: ScreenArguments(title: title, emoji: categoryIcon, documentId: documentId));
            },
          ),
        ],
      ),
      body: SlidingUpPanel(
        backdropEnabled: true,
        borderRadius: radius,
        minHeight: 4.0,
        maxHeight: height * 0.75,
        panel: SlideUpPanel(radius: radius, title: title, documentId: documentId),
        collapsed: CollapsedPanel(radius: radius),
        body: isLoading
            ? Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  SpinKitDoubleBounce(
                    color: Colors.white,
                  ),
                  SizedBox(height: 42.0),
                ],
              )
            : Padding(
                padding: const EdgeInsets.all(16.0),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: <Widget>[
                    Text(
                      title.toString(),
                      style: TextStyle(fontSize: 26.0, fontWeight: FontWeight.bold, decoration: TextDecoration.underline),
                      textAlign: TextAlign.center,
                    ),
                    tslDays > 100
                        ? Text(timeAgoBuilder(lastTsl), style: TextStyle(fontSize: 48.0, fontWeight: FontWeight.bold))
                        : RichText(
                            text: TextSpan(
                              children: <TextSpan>[
                                TextSpan(
                                  text: tslDays < 10 ? '   0$tslDays' : '   $tslDays',
                                  style: TextStyle(fontSize: 40.0, fontWeight: FontWeight.bold),
                                ),
                                TextSpan(
                                  text: ' Days\n',
                                  style: TextStyle(fontSize: 16.0),
                                ),
                                TextSpan(
                                  text: tslHours < 10 ? '   0$tslHours' : '   $tslHours',
                                  style: TextStyle(fontSize: 40.0, fontWeight: FontWeight.bold),
                                ),
                                TextSpan(
                                  text: ' Hours\n',
                                  style: TextStyle(fontSize: 16.0),
                                ),
                                TextSpan(
                                  text: tslMinutes < 10 ? '   0$tslMinutes' : '   $tslMinutes',
                                  style: TextStyle(fontSize: 40.0, fontWeight: FontWeight.bold),
                                ),
                                TextSpan(
                                  text: ' Minutes\n',
                                  style: TextStyle(fontSize: 16.0),
                                ),
                                TextSpan(
                                  text: tslSeconds < 10 ? '   0$tslSeconds' : '   $tslSeconds',
                                  style: TextStyle(fontSize: 40.0, fontWeight: FontWeight.bold),
                                ),
                                TextSpan(
                                  text: ' Seconds\n',
                                  style: TextStyle(fontSize: 16.0),
                                ),
                              ],
                            ),
                          ),
                    ButtonTheme(
                      minWidth: double.infinity,
                      child: RaisedButton(
                        color: Colors.red[900],
                        onPressed: () {
                          HapticFeedback.lightImpact();
                          showDialog(
                            context: context,
                            barrierDismissible: true,
                            builder: (BuildContext context) {
                              return resetTslDialog();
                            },
                          );
                        },
                        elevation: 5.0,
                        //shape: StadiumBorder(),
                        child: Text('RESET'),
                      ),
                    ),
                    Container(
                      height: 42.0,
                      color: Colors.deepOrange,
                    ),
                  ],
                ),
              ),
      ),
    );

Close panel with scrollable content without need of an empty space.

It would be nice if we could close the panel that has scrollable content without needing the empty space. The idea is quite simple: when you can't scroll up the content anymore, the panel should start to close (just like it is with Google Map). The execution though, is quite hard. I tried creating a package from ground up with this feature in mind, but I couldn't do it.

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. :)

Accessibility support (Talkback)

Hi,
Thanks for great package. Has anyone notice that Talkback behaves weird with sliding panel. The body widget is hard to focus. I have a listview widget in the sliding panel body. When I focus on the listview, it doesn't get focused, however if I swipe right it goes through the list.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.