Merge pull request #3039 from abarth/more_snack_bar
Don't delay between dismissing a snack bar and the next snack bar
This commit is contained in:
commit
f3d95b6f28
@ -125,6 +125,7 @@ class SnackBar extends StatelessWidget {
|
|||||||
child: new Dismissable(
|
child: new Dismissable(
|
||||||
key: new Key('dismissable'),
|
key: new Key('dismissable'),
|
||||||
direction: DismissDirection.down,
|
direction: DismissDirection.down,
|
||||||
|
resizeDuration: null,
|
||||||
onDismissed: (DismissDirection direction) {
|
onDismissed: (DismissDirection direction) {
|
||||||
Scaffold.of(context).removeCurrentSnackBar();
|
Scaffold.of(context).removeCurrentSnackBar();
|
||||||
},
|
},
|
||||||
|
@ -8,7 +8,6 @@ import 'framework.dart';
|
|||||||
import 'gesture_detector.dart';
|
import 'gesture_detector.dart';
|
||||||
|
|
||||||
const Duration _kDismissDuration = const Duration(milliseconds: 200);
|
const Duration _kDismissDuration = const Duration(milliseconds: 200);
|
||||||
const Duration _kResizeDuration = const Duration(milliseconds: 300);
|
|
||||||
const Curve _kResizeTimeCurve = const Interval(0.4, 1.0, curve: Curves.ease);
|
const Curve _kResizeTimeCurve = const Interval(0.4, 1.0, curve: Curves.ease);
|
||||||
const double _kMinFlingVelocity = 700.0;
|
const double _kMinFlingVelocity = 700.0;
|
||||||
const double _kMinFlingVelocityDelta = 400.0;
|
const double _kMinFlingVelocityDelta = 400.0;
|
||||||
@ -43,17 +42,19 @@ enum DismissDirection {
|
|||||||
/// Can be dismissed by dragging in the indicated [direction].
|
/// Can be dismissed by dragging in the indicated [direction].
|
||||||
///
|
///
|
||||||
/// Dragging or flinging this widget in the [DismissDirection] causes the child
|
/// Dragging or flinging this widget in the [DismissDirection] causes the child
|
||||||
/// to slide out of view. Following the slide animation, the Dismissable widget
|
/// to slide out of view. Following the slide animation, if [resizeDuration] is
|
||||||
/// animates its height (or width, whichever is perpendicular to the dismiss
|
/// non-null, the Dismissable widget animates its height (or width, whichever is
|
||||||
/// direction) to zero.
|
/// perpendicular to the dismiss direction) to zero over the [resizeDuration].
|
||||||
///
|
///
|
||||||
/// Backgrounds can be used to implement the "leave-behind" idiom. If a background
|
/// Backgrounds can be used to implement the "leave-behind" idiom. If a background
|
||||||
/// is specified it is stacked behind the Dismissable's child and is exposed when
|
/// is specified it is stacked behind the Dismissable's child and is exposed when
|
||||||
/// the child moves.
|
/// the child moves.
|
||||||
///
|
///
|
||||||
/// The [onDimissed] callback runs after Dismissable's size has collapsed to zero.
|
/// The widget calls the [onDimissed] callback either after its size has
|
||||||
/// If the Dismissable is a list item, it must have a key that distinguishes it from
|
/// collapsed to zero (if [resizeDuration] is non-null) or immediately after
|
||||||
/// the other items and its onDismissed callback must remove the item from the list.
|
/// the slide animation (if [resizeDuration] is null). If the Dismissable is a
|
||||||
|
/// list item, it must have a key that distinguishes it from the other items and
|
||||||
|
/// its [onDismissed] callback must remove the item from the list.
|
||||||
class Dismissable extends StatefulWidget {
|
class Dismissable extends StatefulWidget {
|
||||||
Dismissable({
|
Dismissable({
|
||||||
Key key,
|
Key key,
|
||||||
@ -62,7 +63,8 @@ class Dismissable extends StatefulWidget {
|
|||||||
this.secondaryBackground,
|
this.secondaryBackground,
|
||||||
this.onResize,
|
this.onResize,
|
||||||
this.onDismissed,
|
this.onDismissed,
|
||||||
this.direction: DismissDirection.horizontal
|
this.direction: DismissDirection.horizontal,
|
||||||
|
this.resizeDuration: const Duration(milliseconds: 300)
|
||||||
}) : super(key: key) {
|
}) : super(key: key) {
|
||||||
assert(key != null);
|
assert(key != null);
|
||||||
assert(secondaryBackground != null ? background != null : true);
|
assert(secondaryBackground != null ? background != null : true);
|
||||||
@ -90,6 +92,12 @@ class Dismissable extends StatefulWidget {
|
|||||||
/// The direction in which the widget can be dismissed.
|
/// The direction in which the widget can be dismissed.
|
||||||
final DismissDirection direction;
|
final DismissDirection direction;
|
||||||
|
|
||||||
|
/// The amount of time the widget will spend contracting before [onDismissed] is called.
|
||||||
|
///
|
||||||
|
/// If null, the widget will not contract and [onDismissed] will be called
|
||||||
|
/// immediately after the the widget is dismissed.
|
||||||
|
final Duration resizeDuration;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_DismissableState createState() => new _DismissableState();
|
_DismissableState createState() => new _DismissableState();
|
||||||
}
|
}
|
||||||
@ -253,18 +261,23 @@ class _DismissableState extends State<Dismissable> {
|
|||||||
assert(_moveController != null);
|
assert(_moveController != null);
|
||||||
assert(_moveController.isCompleted);
|
assert(_moveController.isCompleted);
|
||||||
assert(_resizeController == null);
|
assert(_resizeController == null);
|
||||||
_resizeController = new AnimationController(duration: _kResizeDuration)
|
if (config.resizeDuration == null) {
|
||||||
..addListener(_handleResizeProgressChanged);
|
if (config.onDismissed != null)
|
||||||
_resizeController.forward();
|
config.onDismissed(_dismissDirection);
|
||||||
setState(() {
|
} else {
|
||||||
_resizeAnimation = new Tween<double>(
|
_resizeController = new AnimationController(duration: config.resizeDuration)
|
||||||
begin: 1.0,
|
..addListener(_handleResizeProgressChanged);
|
||||||
end: 0.0
|
_resizeController.forward();
|
||||||
).animate(new CurvedAnimation(
|
setState(() {
|
||||||
parent: _resizeController,
|
_resizeAnimation = new Tween<double>(
|
||||||
curve: _kResizeTimeCurve
|
begin: 1.0,
|
||||||
));
|
end: 0.0
|
||||||
});
|
).animate(new CurvedAnimation(
|
||||||
|
parent: _resizeController,
|
||||||
|
curve: _kResizeTimeCurve
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleResizeProgressChanged() {
|
void _handleResizeProgressChanged() {
|
||||||
|
@ -230,4 +230,56 @@ void main() {
|
|||||||
expect(tester.findText('bar2'), isNull);
|
expect(tester.findText('bar2'), isNull);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('SnackBar dismiss test', () {
|
||||||
|
testWidgets((WidgetTester tester) {
|
||||||
|
int snackBarCount = 0;
|
||||||
|
Key tapTarget = new Key('tap-target');
|
||||||
|
tester.pumpWidget(new MaterialApp(
|
||||||
|
routes: <String, WidgetBuilder>{
|
||||||
|
'/': (BuildContext context) {
|
||||||
|
return new Scaffold(
|
||||||
|
body: new Builder(
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return new GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
snackBarCount += 1;
|
||||||
|
Scaffold.of(context).showSnackBar(new SnackBar(
|
||||||
|
content: new Text("bar$snackBarCount"),
|
||||||
|
duration: new Duration(seconds: 2)
|
||||||
|
));
|
||||||
|
},
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
|
child: new Container(
|
||||||
|
height: 100.0,
|
||||||
|
width: 100.0,
|
||||||
|
key: tapTarget
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
expect(tester.findText('bar1'), isNull);
|
||||||
|
expect(tester.findText('bar2'), isNull);
|
||||||
|
tester.tap(tester.findElementByKey(tapTarget)); // queue bar1
|
||||||
|
tester.tap(tester.findElementByKey(tapTarget)); // queue bar2
|
||||||
|
expect(tester.findText('bar1'), isNull);
|
||||||
|
expect(tester.findText('bar2'), isNull);
|
||||||
|
tester.pump(); // schedule animation for bar1
|
||||||
|
expect(tester.findText('bar1'), isNotNull);
|
||||||
|
expect(tester.findText('bar2'), isNull);
|
||||||
|
tester.pump(); // begin animation
|
||||||
|
expect(tester.findText('bar1'), isNotNull);
|
||||||
|
expect(tester.findText('bar2'), isNull);
|
||||||
|
tester.pump(new Duration(milliseconds: 750)); // 0.75s // animation last frame; two second timer starts here
|
||||||
|
tester.scroll(tester.findText('bar1'), new Offset(0.0, 50.0));
|
||||||
|
tester.pump(); // bar1 dismissed, bar2 begins animating
|
||||||
|
expect(tester.findText('bar1'), isNull);
|
||||||
|
expect(tester.findText('bar2'), isNotNull);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user