Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 60 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,35 @@

A widget that can be dragged and scrolled in a single gesture and snapped to a list of extents.

<a href="https://github.com/bnxm/sliding_sheet/blob/master/example/lib/main.dart">
<img width="205px" alt="Example of a SlidingSheet" src="https://raw.githubusercontent.com/bnxm/sliding_sheet/master/assets/example.gif"/>
<a href="https://github.com/flutterwtf/sliding_sheet/blob/master/example/lib/main.dart">
<img width="205px" alt="Example of a SlidingSheet" src="images/example_preview.gif"/>
</a>

Click [here](https://github.com/bnxm/sliding_sheet/blob/master/example/lib/main.dart) to view the full example.
Click [here](https://github.com/flutterwtf/sliding_sheet/blob/master/example/lib/main.dart) to view the full example.

The package is a fork of [this](https://github.com/tchigher/sliding-sheet) repository.

## Installing

Add it to your `pubspec.yaml` file:

```yaml
dependencies:
sliding_sheet: ^0.5.0
wtf_sliding_sheet: ^0.6.0
```

Install packages from the command line
```

```shell
flutter packages get
```

If you like this package, consider supporting it by giving it a star on [GitHub](https://github.com/bnxm/sliding_sheet) and a like on [pub.dev](https://pub.dev/packages/sliding_sheet) :heart:
If you like this package, consider supporting it by giving it a star on [GitHub](https://github.com/flutterwtf/sliding_sheet) and a like on [pub.dev](https://pub.dev/packages/wtf_sliding_sheet) :heart:

## Usage

There are two ways in which you can use a `SlidingSheet`: either as a permanent (or persistent) `Widget` in your
widget tree or as a `BottomSheetDialog`.
widget tree or as a `BottomSheetDialog`.

### As a Widget

Expand Down Expand Up @@ -72,15 +77,16 @@ Widget build(BuildContext context) {
}
```

#### Result:
<img width="205px" alt="Example" src="https://raw.githubusercontent.com/bnxm/sliding_sheet/master/assets/usage_example.gif" href/>
**Result:**

<img width="205px" alt="Example" src="images/example_as_a_widget.gif"/>

### As a BottomSheetDialog

This method can be used to show a `SlidingSheet` as a `BottomSheetDialog` by calling the `showSlidingBottomSheet` function and returning and instance of `SlidingSheetDialog`.

```dart
void showAsBottomSheet() async {
void showAsBottomSheet(BuildContext context) async {
final result = await showSlidingBottomSheet(
context,
builder: (context) {
Expand All @@ -103,7 +109,7 @@ void showAsBottomSheet() async {
padding: const EdgeInsets.all(16),
child: Text(
'This is the content of the sheet',
style: Theme.of(context).textTheme.body1,
style: Theme.of(context).textTheme.bodyMedium,
),
),
),
Expand All @@ -118,43 +124,45 @@ void showAsBottomSheet() async {
print(result); // This is the result.
}
```
#### Result:
<img width="205px" alt="Example" src="https://raw.githubusercontent.com/bnxm/sliding_sheet/master/assets/usage_example_bottom_sheet.gif"/>

**Result:**

<img width="205px" alt="Example" src="images/example_as_a_bottom_sheet_dialog.gif"/>

### Snapping

A `SlidingSheet` can snap to multiple extents or to no at all. You can customize the snapping behavior by
passing an instance of `SnapSpec` to the `SlidingSheet`.

Parameter | Description
Parameter | Description
--- | ---
snap | If true, the `SlidingSheet` will snap to the provided `snappings`. If false, the `SlidingSheet` will slide from minExtent to maxExtent and then begin to scroll, if the content is bigger than the available height.
snappings | The extents that the `SlidingSheet` will snap to, when the user ends a drag interaction. The minimum and maximum values will represent the bounds in which the `SlidingSheet` will slide until it reaches the maximum from which on it will scroll.
positioning | Can be set to one of these three values: `SnapPositioning.relativeToAvailableSpace` - Positions the snaps relative to total available height that the `SlidingSheet` can expand to. All values must be between 0 and 1. E.g. a snap of `0.5` in a `Scaffold` without an `AppBar` would mean that the snap would be positioned at 40% of the screen height, irrespective of the height of the `SlidingSheet`. `SnapPositioning.relativeToSheetHeight` - Positions the snaps relative to the total height of the sheet. All values must be between 0 and 1. E.g. a snap of `0.5` and a total sheet size of 300 pixels would mean the snap would be positioned at a 150 pixel offset from the bottom. `SnapPositioning.pixelOffset` - Positions the snaps at a fixed pixel offset. `double.infinity` can be used to refer to the total available space without having to compute it yourself.
onSnap | A callback function that gets invoked when the `SlidingSheet` snaps to an extent.

<p float="left">
<img width="205px" alt="SnapPositioning.relativeToAvailableSpace with a snap of 0.5" src="https://raw.githubusercontent.com/bnxm/sliding_sheet/master/assets/example_snapping_relativeToAvailableSpace.png"/>
<img width="205px" alt="SnapPositioning.relativeToSheetHeight with a snap of 0.5" src="https://raw.githubusercontent.com/bnxm/sliding_sheet/master/assets/example_snapping_relativeToSheetHeight.png"/>
<img width="205px" alt="SnapPositioning.pixelOffset with a snap of 100" src="https://raw.githubusercontent.com/bnxm/sliding_sheet/master/assets/example_snapping_pixelOffset.png"/>
<img width="205px" alt="SnapPositioning.relativeToAvailableSpace with a snap of 0.5" src="images/example_snap_relative_to_space.png"/>
<img width="205px" alt="SnapPositioning.relativeToSheetHeight with a snap of 0.5" src="images/example_snap_relative_to_height.png"/>
<img width="205px" alt="SnapPositioning.pixelOffset with a snap of 100" src="images/example_snap_to_pixel_offset.png"/>
</p>

There are also some prebuild snaps you can facilitate to snap for example to headers or footers as shown in the example.

Snap | Description
Snap | Description
--- | ---
SnapSpec.headerFooterSnap | The snap extent that makes header and footer fully visible without account for vertical padding on the `SlidingSheet`.
SnapSpec.headerSnap | The snap extent that makes the header fully visible without account for top padding on the `SlidingSheet`.
SnapSpec.footerSnap | The snap extent that makes the footer fully visible without account for bottom padding on the `SlidingSheet`.
SnapSpec.expanded | The snap extent that expands the whole `SlidingSheet`.
`SnapSpec.headerFooterSnap` | The snap extent that makes header and footer fully visible without account for vertical padding on the `SlidingSheet`.
`SnapSpec.headerSnap` | The snap extent that makes the header fully visible without account for top padding on the `SlidingSheet`.
`SnapSpec.footerSnap` | The snap extent that makes the footer fully visible without account for bottom padding on the `SlidingSheet`.
`SnapSpec.expanded` | The snap extent that expands the whole `SlidingSheet`.

### SheetController

The `SheetController` can be used to change the state of a `SlidingSheet` manually, simply passing an instance of `SheetController` to a `SlidingSheet`. Note that the methods can only be used after the `SlidingSheet` has been rendered, however calling them before wont throw an exception.

Note that you can also use the static `SheetController.of(context)` method to obtain an instance of the `SheetController` of the closest `SlidingSheet`. This also works if you didn't assign a `SheetController` explicitly on the `SlidingSheet`.

Method | Description
Method | Description
--- | ---
`expand()` | Expands the `SlidingSheet` to the maximum extent.
`collapse()` | Collapses the `SlidingSheet` to the minimum extent.
Expand Down Expand Up @@ -192,7 +200,7 @@ Widget build(BuildContext context) {
child: Center(
child: Text(
'This is the content of the sheet',
style: Theme.of(context).textTheme.body1,
style: Theme.of(context).textTheme.bodyMedium,
),
),
);
Expand All @@ -205,7 +213,7 @@ Widget build(BuildContext context) {
alignment: Alignment.center,
child: Text(
'This is the header',
style: Theme.of(context).textTheme.body1.copyWith(color: Colors.white),
style: Theme.of(context).textTheme.bodyMedium.copyWith(color: Colors.white),
),
);
},
Expand All @@ -217,7 +225,7 @@ Widget build(BuildContext context) {
alignment: Alignment.center,
child: Text(
'This is the footer',
style: Theme.of(context).textTheme.body1.copyWith(color: Colors.black),
style: Theme.of(context).textTheme.bodyMedium.copyWith(color: Colors.black),
),
);
},
Expand All @@ -227,8 +235,10 @@ Widget build(BuildContext context) {
);
}
```
#### Result:
<img width="205px" alt="Simple header/footer example" src="https://raw.githubusercontent.com/bnxm/sliding_sheet/master/assets/example_header_footer.gif"/>

**Result:**

<img width="205px" alt="Simple header/footer example" src="images/example_header_footer.gif"/>

### ListViews and Columns

Expand All @@ -240,22 +250,33 @@ In order to change the UI when the sheet gets interacted with, you can pass a ca

For rebuilding individual children of a `SlidingSheet` (e.g. elevating the header when content gets scrolled under it), you can also use the `SheetListenerBuilder`:

~~~dart
```dart
return SheetListenerBuilder(
// buildWhen can be used to only rebuild the widget when needed.
buildWhen: (oldState, newState) => oldState.isAtTop != newState.isAtTop,
builder: (context, state) {
return AnimatedContainer(
elevation: !state.isAtTop ? elevation : 0.0,
duration: const Duration(milliseconds: 400),
child: child,
buildWhen: (oldState, newState) =>
oldState.progress != newState.progress,
builder: (context, SheetState state) {
return Material(
elevation: state.progress * 20 + 1,
color: Colors.lightBlue,
borderRadius: BorderRadius.vertical(
top: Radius.circular(16),
),
child: SizedBox(
height: 60,
child: Center(
child: const Text('Header'),
),
),
);
},
);
~~~
```

The example for instance decreases the corner radius of the `SlidingSheet` as it gets dragged to the top and increases the headers top padding by the status bar height. Also, when content gets scrolled under the header it elevates.
**Result:**

Because these are common Material behaviors, `SlidingSheet` supports those out of the box, which can be achieved by setting the `avoidStatusBar` field to `true`, `cornerRadiusOnFullscreen` to `0` and `liftOnScrollHeaderElevation` to the elevation.
<img width="205px" alt="Example of Material Effects" src="images/example_material_effects.gif"/>

<img width="205px" alt="Example of Material Effects" src="https://raw.githubusercontent.com/bnxm/sliding_sheet/master/assets/example_reflecting_changes.gif"/>
The [example](https://github.com/flutterwtf/sliding_sheet/blob/master/example/lib/main.dart) for instance decreases the corner radius of the `SlidingSheet` as it gets dragged to the top and increases the headers top padding by the status bar height. Also, when content gets scrolled under the header it elevates.

Because these are common Material behaviors, `SlidingSheet` supports those out of the box, which can be achieved by setting the `avoidStatusBar` field to `true`, `cornerRadiusOnFullscreen` to `0` and `liftOnScrollHeaderElevation` to the elevation.
7 changes: 0 additions & 7 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -327,13 +327,6 @@ linter:
# https://dart-lang.github.io/linter/lints/implementation_imports.html
- implementation_imports

# Although there are some false positives, this lint generally catches unnecessary checks
# - https://github.com/dart-lang/linter/issues/811
#
# pedantic: disabled
# https://dart-lang.github.io/linter/lints/invariant_booleans.html
- invariant_booleans

# Type check for Iterable<T>.contains(other) where other is! T
# otherwise contains will always report false. Those errors are usually very hard to catch.
# https://dart-lang.github.io/linter/lints/iterable_contains_unrelated_type.html
Expand Down
26 changes: 23 additions & 3 deletions example/.metadata
Original file line number Diff line number Diff line change
@@ -1,10 +1,30 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
# This file should be version controlled.

version:
revision: e70236e36ce1d32067dc68eb55519ec3e14b6b01
channel: beta
revision: 12cb4eb7a009f52b347b62ade7cb4854b926af72
channel: stable

project_type: app

# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 12cb4eb7a009f52b347b62ade7cb4854b926af72
base_revision: 12cb4eb7a009f52b347b62ade7cb4854b926af72
- platform: android
create_revision: 12cb4eb7a009f52b347b62ade7cb4854b926af72
base_revision: 12cb4eb7a009f52b347b62ade7cb4854b926af72

# User provided section

# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
29 changes: 29 additions & 0 deletions example/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.

# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml

linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
6 changes: 6 additions & 0 deletions example/android/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@ gradle-wrapper.jar
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java

# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks
17 changes: 0 additions & 17 deletions example/android/.project

This file was deleted.

2 changes: 0 additions & 2 deletions example/android/.settings/org.eclipse.buildship.core.prefs

This file was deleted.

6 changes: 0 additions & 6 deletions example/android/app/.classpath

This file was deleted.

23 changes: 0 additions & 23 deletions example/android/app/.project

This file was deleted.

This file was deleted.

Loading