Toggle navigation
Toggle navigation
This project
Loading...
Sign in
flutter_package
/
modal_bottom_sheet
Go to a project
Toggle navigation
Projects
Groups
Snippets
Help
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
Jaime Blasco
2020-07-05 17:57:12 +0200
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
28a8d71e5fb379a8eaf48f8356d9f37bff31b6e6
28a8d71e
1 parent
200f2082
Add custom curve when not dragging
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
154 additions
and
54 deletions
example/lib/examples/cupertino_share.dart
example/lib/main.dart
example/lib/modals/modal_with_nested_scroll.dart
lib/src/bottom_sheet.dart
lib/src/utils/bottom_sheet_suspended_curve.dart
example/lib/examples/cupertino_share.dart
View file @
28a8d71
...
...
@@ -8,6 +8,7 @@ import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
class
CupertinoSharePage
extends
StatelessWidget
{
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
appBar:
appBar
(
context
),
body:
CupertinoPageScaffold
(
...
...
example/lib/main.dart
View file @
28a8d71
...
...
@@ -162,6 +162,7 @@ class _MyHomePageState extends State<MyHomePage> {
title:
Text
(
'Cupertino Modal fit'
),
onTap:
()
=>
showCupertinoModalBottomSheet
(
expand:
false
,
context:
context
,
backgroundColor:
Colors
.
transparent
,
builder:
(
context
,
scrollController
)
=>
...
...
@@ -173,6 +174,7 @@ class _MyHomePageState extends State<MyHomePage> {
onTap:
()
=>
showCupertinoModalBottomSheet
(
expand:
true
,
context:
context
,
animationCurve:
Curves
.
easeInOutCubic
,
backgroundColor:
Colors
.
transparent
,
builder:
(
context
,
scrollController
)
=>
ModalFit
(
scrollController:
scrollController
),
...
...
example/lib/modals/modal_with_nested_scroll.dart
View file @
28a8d71
...
...
@@ -9,28 +9,29 @@ class NestedScrollModal extends StatelessWidget {
@override
Widget
build
(
BuildContext
context
)
{
return
NestedScrollView
(
physics:
ScrollPhysics
(
parent:
PageScrollPhysics
()),
headerSliverBuilder:
(
BuildContext
context
,
bool
innerBoxIsScrolled
)
{
return
<
Widget
>[
SliverList
(
delegate:
SliverChildListDelegate
(
[
Container
(
height:
300
,
color:
Colors
.
blue
),
],
),
controller:
ScrollController
(),
physics:
ScrollPhysics
(
parent:
PageScrollPhysics
()),
headerSliverBuilder:
(
BuildContext
context
,
bool
innerBoxIsScrolled
)
{
return
<
Widget
>[
SliverList
(
delegate:
SliverChildListDelegate
(
[
Container
(
height:
300
,
color:
Colors
.
blue
),
],
),
];
),
];
},
body:
ListView
.
builder
(
controller:
scrollController
,
itemBuilder:
(
context
,
index
)
{
return
Container
(
height:
100
,
color:
index
.
isOdd
?
Colors
.
green
:
Colors
.
orange
,
);
},
body:
ListView
.
builder
(
controller:
scrollController
,
itemBuilder:
(
context
,
index
)
{
return
Container
(
height:
100
,
color:
index
.
isOdd
?
Colors
.
green
:
Colors
.
orange
,
);
},
itemCount:
12
,
));
itemCount:
12
,
),
);
}
}
...
...
lib/src/bottom_sheet.dart
View file @
28a8d71
...
...
@@ -11,6 +11,12 @@ import 'package:flutter/material.dart';
import
'package:flutter/scheduler.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:modal_bottom_sheet/src/utils/bottom_sheet_suspended_curve.dart'
;
import
'package:modal_bottom_sheet/src/utils/primary_scroll_status_bar.dart'
;
const
Curve
_decelerateEasing
=
Cubic
(
0.0
,
0.0
,
0.2
,
1.0
);
const
Curve
_modalBottomSheetCurve
=
_decelerateEasing
;
const
Duration
_bottomSheetDuration
=
Duration
(
milliseconds:
400
);
const
double
_minFlingVelocity
=
500.0
;
const
double
_closeProgressThreshold
=
0.6
;
...
...
@@ -61,7 +67,7 @@ class ModalBottomSheet extends StatefulWidget {
/// The curve used by the animation showing and dismissing the bottom sheet.
///
/// If no curve is provided it falls back to `
Curves.easeOutSine
`.
/// If no curve is provided it falls back to `
decelerateEasing
`.
final
Curve
animationCurve
;
/// Allows the bottom sheet to go beyond the top bound of the content,
...
...
@@ -176,7 +182,10 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
return
result
;
}
ParametricCurve
<
double
>
animationCurve
;
void
_handleDragUpdate
(
double
primaryDelta
)
async
{
animationCurve
=
Curves
.
linear
;
assert
(
widget
.
enableDrag
,
'Dragging is disabled'
);
if
(
_dismissUnderway
)
return
;
...
...
@@ -210,6 +219,11 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
void
_handleDragEnd
(
double
velocity
)
async
{
assert
(
widget
.
enableDrag
,
'Dragging is disabled'
);
animationCurve
=
BottomSheetSuspendedCurve
(
widget
.
animationController
.
value
,
curve:
_defaultCurve
,
);
if
(
_dismissUnderway
||
!
isDragging
)
return
;
isDragging
=
false
;
_bounceDragController
.
reverse
();
...
...
@@ -302,8 +316,12 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
}
}
ParametricCurve
<
double
>
get
_defaultCurve
=>
widget
.
animationCurve
??
_modalBottomSheetCurve
;
@override
void
initState
()
{
animationCurve
=
_defaultCurve
;
_bounceDragController
=
AnimationController
(
vsync:
this
,
duration:
Duration
(
milliseconds:
300
));
_scrollController
=
widget
.
scrollController
??
ScrollController
();
...
...
@@ -328,45 +346,57 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
);
}
// Todo: Add curved Animation when push and pop without gesture
final
Animation
<
double
>
containerAnimation
=
CurvedAnimation
(
parent:
widget
.
animationController
,
curve:
widget
.
animationCurve
??
Curves
.
linear
,
);
final
mediaQuery
=
MediaQuery
.
of
(
context
);
return
AnimatedBuilder
(
child
=
AnimatedBuilder
(
animation:
widget
.
animationController
,
builder:
(
context
,
_
)
=>
ClipRect
(
child:
CustomSingleChildLayout
(
delegate:
_ModalBottomSheetLayout
(
containerAnimation
.
value
,
widget
.
expanded
),
child:
!
widget
.
enableDrag
?
child
:
KeyedSubtree
(
key:
_childKey
,
child:
AnimatedBuilder
(
animation:
bounceAnimation
,
builder:
(
context
,
_
)
=>
CustomSingleChildLayout
(
delegate:
_CustomBottomSheetLayout
(
bounceAnimation
.
value
),
child:
GestureDetector
(
onVerticalDragUpdate:
(
details
)
=>
_handleDragUpdate
(
details
.
primaryDelta
),
onVerticalDragEnd:
(
details
)
=>
_handleDragEnd
(
details
.
primaryVelocity
),
child:
NotificationListener
<
ScrollNotification
>(
onNotification:
(
ScrollNotification
notification
)
{
_handleScrollUpdate
(
notification
);
return
false
;
},
child:
child
,
),
builder:
(
context
,
child
)
{
final
animationValue
=
animationCurve
.
transform
(
mediaQuery
.
accessibleNavigation
?
1.0
:
widget
.
animationController
.
value
);
final
draggableChild
=
!
widget
.
enableDrag
?
child
:
KeyedSubtree
(
key:
_childKey
,
child:
AnimatedBuilder
(
animation:
bounceAnimation
,
builder:
(
context
,
_
)
=>
CustomSingleChildLayout
(
delegate:
_CustomBottomSheetLayout
(
bounceAnimation
.
value
),
child:
GestureDetector
(
onVerticalDragUpdate:
(
details
)
{
_handleDragUpdate
(
details
.
primaryDelta
);
},
onVerticalDragEnd:
(
details
)
{
_handleDragEnd
(
details
.
primaryVelocity
);
},
child:
NotificationListener
<
ScrollNotification
>(
onNotification:
(
ScrollNotification
notification
)
{
_handleScrollUpdate
(
notification
);
return
false
;
},
child:
child
,
),
),
),
),
),
),
);
return
ClipRect
(
child:
CustomSingleChildLayout
(
delegate:
_ModalBottomSheetLayout
(
animationValue
,
widget
.
expanded
,
),
child:
draggableChild
,
),
);
},
child:
RepaintBoundary
(
child:
child
),
);
return
PrimaryScrollStatusBarHandler
(
scrollController:
_scrollController
,
child:
child
);
}
}
...
...
lib/src/utils/bottom_sheet_suspended_curve.dart
0 → 100644
View file @
28a8d71
import
'dart:ui'
;
import
'package:flutter/animation.dart'
;
import
'package:flutter/foundation.dart'
;
// Copied from bottom_sheet.dart as is a private class
// https://github.com/flutter/flutter/issues/51627
// TODO(guidezpl): Look into making this public. A copy of this class is in
// scaffold.dart, for now, https://github.com/flutter/flutter/issues/51627
/// A curve that progresses linearly until a specified [startingPoint], at which
/// point [curve] will begin. Unlike [Interval], [curve] will not start at zero,
/// but will use [startingPoint] as the Y position.
///
/// For example, if [startingPoint] is set to `0.5`, and [curve] is set to
/// [Curves.easeOut], then the bottom-left quarter of the curve will be a
/// straight line, and the top-right quarter will contain the entire contents of
/// [Curves.easeOut].
///
/// This is useful in situations where a widget must track the user's finger
/// (which requires a linear animation), and afterwards can be flung using a
/// curve specified with the [curve] argument, after the finger is released. In
/// such a case, the value of [startingPoint] would be the progress of the
/// animation at the time when the finger was released.
///
/// The [startingPoint] and [curve] arguments must not be null.
class
BottomSheetSuspendedCurve
extends
ParametricCurve
<
double
>
{
/// Creates a suspended curve.
const
BottomSheetSuspendedCurve
(
this
.
startingPoint
,
{
this
.
curve
=
Curves
.
easeOutCubic
,
})
:
assert
(
startingPoint
!=
null
),
assert
(
curve
!=
null
);
/// The progress value at which [curve] should begin.
///
/// This defaults to [Curves.easeOutCubic].
final
double
startingPoint
;
/// The curve to use when [startingPoint] is reached.
final
Curve
curve
;
@override
double
transform
(
double
t
)
{
assert
(
t
>=
0.0
&&
t
<=
1.0
);
assert
(
startingPoint
>=
0.0
&&
startingPoint
<=
1.0
);
if
(
t
<
startingPoint
)
{
return
t
;
}
if
(
t
==
1.0
)
{
return
t
;
}
final
double
curveProgress
=
(
t
-
startingPoint
)
/
(
1
-
startingPoint
);
final
double
transformed
=
curve
.
transform
(
curveProgress
);
return
lerpDouble
(
startingPoint
,
1
,
transformed
);
}
@override
String
toString
()
{
return
'
${describeIdentity(this)}
(
$startingPoint
,
$curve
)'
;
}
}
...
...
Please
register
or
login
to post a comment