1
0
mirror of https://github.com/flutter/samples.git synced 2026-05-15 11:27:58 +00:00

[Shrine] New Shrine with expanding cart bottom sheet from experimenal (#18)

This commit is contained in:
Will Larche
2018-09-27 11:36:30 -04:00
committed by Andrew Brogdon
parent b5ce05e934
commit 4b4d5fef9c
11 changed files with 857 additions and 88 deletions

View File

@@ -16,9 +16,11 @@ import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
import 'login.dart';
import 'shopping_cart.dart';
const double _kFlingVelocity = 2.0;
const Cubic _kAccelerateCurve = Cubic(0.548, 0.0, 0.757, 0.464);
const Cubic _kDecelerateCurve = Cubic(0.23, 0.94, 0.41, 1.0);
const double _kPeakVelocityTime = 0.248210;
const double _kPeakVelocityProgress = 0.379146;
class _FrontLayer extends StatelessWidget {
const _FrontLayer({
@@ -74,7 +76,10 @@ class _BackdropTitle extends AnimatedWidget {
@override
Widget build(BuildContext context) {
final Animation<double> animation = this.listenable;
final Animation<double> animation = CurvedAnimation(
parent: this.listenable,
curve: Interval(0.0, 0.78),
);
return DefaultTextStyle(
style: Theme.of(context).primaryTextTheme.title,
@@ -150,16 +155,19 @@ class Backdrop extends StatefulWidget {
final Widget backLayer;
final Widget frontTitle;
final Widget backTitle;
final AnimationController controller;
const Backdrop({
@required this.frontLayer,
@required this.backLayer,
@required this.frontTitle,
@required this.backTitle,
@required this.controller,
}) : assert(frontLayer != null),
assert(backLayer != null),
assert(frontTitle != null),
assert(backTitle != null);
assert(backTitle != null),
assert(controller != null);
@override
_BackdropState createState() => _BackdropState();
@@ -169,15 +177,12 @@ class _BackdropState extends State<Backdrop>
with SingleTickerProviderStateMixin {
final GlobalKey _backdropKey = GlobalKey(debugLabel: 'Backdrop');
AnimationController _controller;
Animation<RelativeRect> _layerAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(milliseconds: 300),
value: 1.0,
vsync: this,
);
_controller = widget.controller;
}
@override
@@ -193,8 +198,73 @@ class _BackdropState extends State<Backdrop>
}
void _toggleBackdropLayerVisibility() {
_controller.fling(
velocity: _frontLayerVisible ? -_kFlingVelocity : _kFlingVelocity);
// Call setState here to update layerAnimation if that's necessary
setState(() {
_frontLayerVisible ? _controller.reverse() : _controller.forward();
});
}
// _layerAnimation animates the front layer between open and close.
// _getLayerAnimation adjusts the values in the TweenSequence so the
// curve and timing are correct in both directions.
Animation<RelativeRect> _getLayerAnimation(Size layerSize, double layerTop) {
Curve firstCurve; // Curve for first TweenSequenceItem
Curve secondCurve; // Curve for second TweenSequenceItem
double firstWeight; // Weight of first TweenSequenceItem
double secondWeight; // Weight of second TweenSequenceItem
Animation animation; // Animation on which TweenSequence runs
if (_frontLayerVisible) {
firstCurve = _kAccelerateCurve;
secondCurve = _kDecelerateCurve;
firstWeight = _kPeakVelocityTime;
secondWeight = 1.0 - _kPeakVelocityTime;
animation = CurvedAnimation(
parent: _controller.view,
curve: Interval(0.0, 0.78),
);
} else {
// These values are only used when the controller runs from t=1.0 to t=0.0
firstCurve = _kDecelerateCurve.flipped;
secondCurve = _kAccelerateCurve.flipped;
firstWeight = 1.0 - _kPeakVelocityTime;
secondWeight = _kPeakVelocityTime;
animation = _controller.view;
}
return TweenSequence(
<TweenSequenceItem<RelativeRect>>[
TweenSequenceItem<RelativeRect>(
tween: RelativeRectTween(
begin: RelativeRect.fromLTRB(
0.0,
layerTop,
0.0,
layerTop - layerSize.height,
),
end: RelativeRect.fromLTRB(
0.0,
layerTop * _kPeakVelocityProgress,
0.0,
(layerTop - layerSize.height) * _kPeakVelocityProgress,
),
).chain(CurveTween(curve: firstCurve)),
weight: firstWeight,
),
TweenSequenceItem<RelativeRect>(
tween: RelativeRectTween(
begin: RelativeRect.fromLTRB(
0.0,
layerTop * _kPeakVelocityProgress,
0.0,
(layerTop - layerSize.height) * _kPeakVelocityProgress,
),
end: RelativeRect.fill,
).chain(CurveTween(curve: secondCurve)),
weight: secondWeight,
),
],
).animate(animation);
}
Widget _buildStack(BuildContext context, BoxConstraints constraints) {
@@ -202,18 +272,14 @@ class _BackdropState extends State<Backdrop>
final Size layerSize = constraints.biggest;
final double layerTop = layerSize.height - layerTitleHeight;
Animation<RelativeRect> layerAnimation = RelativeRectTween(
begin: RelativeRect.fromLTRB(
0.0, layerTop, 0.0, layerTop - layerSize.height),
end: RelativeRect.fromLTRB(0.0, 0.0, 0.0, 0.0),
).animate(_controller.view);
_layerAnimation = _getLayerAnimation(layerSize, layerTop);
return Stack(
key: _backdropKey,
children: <Widget>[
widget.backLayer,
PositionedTransition(
rect: layerAnimation,
rect: _layerAnimation,
child: _FrontLayer(
onTap: _toggleBackdropLayerVisibility,
child: widget.frontLayer,
@@ -237,17 +303,7 @@ class _BackdropState extends State<Backdrop>
),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.shopping_cart),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => ShoppingCartPage()),
);
},
),
IconButton(
icon: const Icon(Icons.search),
icon: const Icon(Icons.search, semanticLabel: 'login'),
onPressed: () {
Navigator.push(
context,
@@ -256,7 +312,7 @@ class _BackdropState extends State<Backdrop>
},
),
IconButton(
icon: const Icon(Icons.tune),
icon: const Icon(Icons.tune, semanticLabel: 'login'),
onPressed: () {
Navigator.push(
context,