Merge pull request #1371 from Hixie/fab-snack
Make the FAB move up when a Snack Bar slides in.
This commit is contained in:
commit
2ed1b60808
@ -236,7 +236,6 @@ class StockHomeState extends State<StockHome> {
|
||||
if (_snackBarStatus == AnimationStatus.dismissed)
|
||||
return null;
|
||||
return new SnackBar(
|
||||
transitionKey: snackBarKey,
|
||||
showing: _isSnackBarShowing,
|
||||
content: new Text("Stock purchased!"),
|
||||
actions: [new SnackBarAction(label: "UNDO", onPressed: _handleUndo)],
|
||||
|
@ -211,7 +211,9 @@ class SizedBox extends OneChildRenderObjectWidget {
|
||||
final double width;
|
||||
final double height;
|
||||
|
||||
RenderConstrainedBox createRenderObject() => new RenderConstrainedBox(additionalConstraints: _additionalConstraints);
|
||||
RenderConstrainedBox createRenderObject() => new RenderConstrainedBox(
|
||||
additionalConstraints: _additionalConstraints
|
||||
);
|
||||
|
||||
BoxConstraints get _additionalConstraints {
|
||||
BoxConstraints result = const BoxConstraints();
|
||||
@ -227,6 +229,24 @@ class SizedBox extends OneChildRenderObjectWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class OverflowBox extends OneChildRenderObjectWidget {
|
||||
OverflowBox({ Key key, this.width, this.height, Widget child })
|
||||
: super(key: key, child: child);
|
||||
|
||||
final double width;
|
||||
final double height;
|
||||
|
||||
RenderOverflowBox createRenderObject() => new RenderOverflowBox(
|
||||
innerWidth: width,
|
||||
innerHeight: height
|
||||
);
|
||||
|
||||
void updateRenderObject(RenderOverflowBox renderObject, OverflowBox oldWidget) {
|
||||
renderObject.innerWidth = width;
|
||||
renderObject.innerHeight = height;
|
||||
}
|
||||
}
|
||||
|
||||
class ConstrainedBox extends OneChildRenderObjectWidget {
|
||||
ConstrainedBox({ Key key, this.constraints, Widget child })
|
||||
: super(key: key, child: child) {
|
||||
|
@ -102,6 +102,7 @@ class RenderScaffold extends RenderBox {
|
||||
void performLayout() {
|
||||
double bodyHeight = size.height;
|
||||
double bodyPosition = 0.0;
|
||||
double fabOffset = 0.0;
|
||||
if (_slots[ScaffoldSlots.statusBar] != null) {
|
||||
RenderBox statusBar = _slots[ScaffoldSlots.statusBar];
|
||||
statusBar.layout(new BoxConstraints.tight(new Size(size.width, kStatusBarHeight)));
|
||||
@ -127,18 +128,20 @@ class RenderScaffold extends RenderBox {
|
||||
if (_slots[ScaffoldSlots.snackBar] != null) {
|
||||
RenderBox snackBar = _slots[ScaffoldSlots.snackBar];
|
||||
// TODO(jackson): On tablet/desktop, minWidth = 288, maxWidth = 568
|
||||
snackBar.layout(new BoxConstraints(minWidth: size.width, maxWidth: size.width, minHeight: 0.0, maxHeight: size.height),
|
||||
parentUsesSize: true);
|
||||
snackBar.layout(
|
||||
new BoxConstraints(minWidth: size.width, maxWidth: size.width, minHeight: 0.0, maxHeight: bodyHeight),
|
||||
parentUsesSize: true
|
||||
);
|
||||
assert(snackBar.parentData is BoxParentData);
|
||||
// Position it off-screen. SnackBar slides in with an animation.
|
||||
snackBar.parentData.position = new Point(0.0, size.height);
|
||||
snackBar.parentData.position = new Point(0.0, bodyPosition + bodyHeight - snackBar.size.height);
|
||||
fabOffset += snackBar.size.height;
|
||||
}
|
||||
if (_slots[ScaffoldSlots.floatingActionButton] != null) {
|
||||
RenderBox floatingActionButton = _slots[ScaffoldSlots.floatingActionButton];
|
||||
Size area = new Size(size.width - kButtonX, size.height - kButtonY);
|
||||
floatingActionButton.layout(new BoxConstraints.loose(area), parentUsesSize: true);
|
||||
assert(floatingActionButton.parentData is BoxParentData);
|
||||
floatingActionButton.parentData.position = (area - floatingActionButton.size).toPoint();
|
||||
floatingActionButton.parentData.position = (area - floatingActionButton.size).toPoint() + new Offset(0.0, -fabOffset);
|
||||
}
|
||||
if (_slots[ScaffoldSlots.drawer] != null) {
|
||||
RenderBox drawer = _slots[ScaffoldSlots.drawer];
|
||||
|
@ -17,7 +17,10 @@ import 'package:sky/src/fn3/transitions.dart';
|
||||
typedef void SnackBarDismissedCallback();
|
||||
|
||||
const Duration _kSlideInDuration = const Duration(milliseconds: 200);
|
||||
// TODO(ianh): factor out some of the constants below
|
||||
const double kSnackHeight = 52.0;
|
||||
const double kSideMargins = 24.0;
|
||||
const double kVerticalPadding = 14.0;
|
||||
const Color kSnackBackground = const Color(0xFF323232);
|
||||
|
||||
class SnackBarAction extends StatelessComponent {
|
||||
SnackBarAction({Key key, this.label, this.onPressed }) : super(key: key) {
|
||||
@ -31,8 +34,8 @@ class SnackBarAction extends StatelessComponent {
|
||||
return new GestureDetector(
|
||||
onTap: onPressed,
|
||||
child: new Container(
|
||||
margin: const EdgeDims.only(left: 24.0),
|
||||
padding: const EdgeDims.only(top: 14.0, bottom: 14.0),
|
||||
margin: const EdgeDims.only(left: kSideMargins),
|
||||
padding: const EdgeDims.symmetric(vertical: kVerticalPadding),
|
||||
child: new Text(label)
|
||||
)
|
||||
);
|
||||
@ -42,7 +45,6 @@ class SnackBarAction extends StatelessComponent {
|
||||
class SnackBar extends AnimatedComponent {
|
||||
SnackBar({
|
||||
Key key,
|
||||
this.transitionKey,
|
||||
this.content,
|
||||
this.actions,
|
||||
bool showing,
|
||||
@ -51,7 +53,6 @@ class SnackBar extends AnimatedComponent {
|
||||
assert(content != null);
|
||||
}
|
||||
|
||||
final Key transitionKey;
|
||||
final Widget content;
|
||||
final List<SnackBarAction> actions;
|
||||
final SnackBarDismissedCallback onDismissed;
|
||||
@ -69,7 +70,7 @@ class SnackBarState extends AnimatedState<SnackBar> {
|
||||
List<Widget> children = [
|
||||
new Flexible(
|
||||
child: new Container(
|
||||
margin: const EdgeDims.symmetric(vertical: 14.0),
|
||||
margin: const EdgeDims.symmetric(vertical: kVerticalPadding),
|
||||
child: new DefaultTextStyle(
|
||||
style: Typography.white.subhead,
|
||||
child: config.content
|
||||
@ -79,24 +80,28 @@ class SnackBarState extends AnimatedState<SnackBar> {
|
||||
];
|
||||
if (config.actions != null)
|
||||
children.addAll(config.actions);
|
||||
return new SlideTransition(
|
||||
key: config.transitionKey,
|
||||
return new SquashTransition(
|
||||
performance: performance.view,
|
||||
position: new AnimatedValue<Point>(
|
||||
Point.origin,
|
||||
end: const Point(0.0, -52.0),
|
||||
height: new AnimatedValue<double>(
|
||||
0.0,
|
||||
end: kSnackHeight,
|
||||
curve: easeIn,
|
||||
reverseCurve: easeOut
|
||||
),
|
||||
child: new Material(
|
||||
level: 2,
|
||||
color: const Color(0xFF323232),
|
||||
type: MaterialType.canvas,
|
||||
child: new Container(
|
||||
margin: const EdgeDims.symmetric(horizontal: 24.0),
|
||||
child: new DefaultTextStyle(
|
||||
style: new TextStyle(color: Theme.of(context).accentColor),
|
||||
child: new Row(children)
|
||||
child: new ClipRect(
|
||||
child: new OverflowBox(
|
||||
height: kSnackHeight,
|
||||
child: new Material(
|
||||
level: 2,
|
||||
color: kSnackBackground,
|
||||
type: MaterialType.canvas,
|
||||
child: new Container(
|
||||
margin: const EdgeDims.symmetric(horizontal: kSideMargins),
|
||||
child: new DefaultTextStyle(
|
||||
style: new TextStyle(color: Theme.of(context).accentColor),
|
||||
child: new Row(children)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -83,7 +83,7 @@ class RenderProxyBox extends RenderBox with RenderObjectWithChildMixin<RenderBox
|
||||
|
||||
/// A render object that imposes additional constraints on its child
|
||||
///
|
||||
/// A render constrainted box proxies most functions in the render box protocol
|
||||
/// A render constrained box proxies most functions in the render box protocol
|
||||
/// to its child, except that when laying out its child, it tightens the
|
||||
/// constraints provided by its parent by enforcing the [additionalConstraints]
|
||||
/// as well.
|
||||
@ -94,7 +94,7 @@ class RenderConstrainedBox extends RenderProxyBox {
|
||||
RenderConstrainedBox({
|
||||
RenderBox child,
|
||||
BoxConstraints additionalConstraints
|
||||
}) : super(child), _additionalConstraints = additionalConstraints {
|
||||
}) : _additionalConstraints = additionalConstraints, super(child) {
|
||||
assert(additionalConstraints != null);
|
||||
}
|
||||
|
||||
@ -145,6 +145,99 @@ class RenderConstrainedBox extends RenderProxyBox {
|
||||
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}additionalConstraints: ${additionalConstraints}\n';
|
||||
}
|
||||
|
||||
/// A render object that imposes different constraints on its child than it gets
|
||||
/// from its parent, possibly allowing the child to overflow the parent.
|
||||
///
|
||||
/// A render overflow box proxies most functions in the render box protocol to
|
||||
/// its child, except that when laying out its child, it passes constraints
|
||||
/// based on the innerWidth and innerHeight fields instead of just passing the
|
||||
/// parent's constraints in. It then sizes itself based on the parent's
|
||||
/// constraints' maxWidth and maxHeight, ignoring the child's dimensions.
|
||||
///
|
||||
/// For example, if you wanted a box to always render 50x50, regardless of where
|
||||
/// it was rendered, you would wrap it in a RenderOverflow with innerWidth and
|
||||
/// innerHeight members set to 50.0. Generally speaking, to avoid confusing
|
||||
/// behaviour around hit testing, a RenderOverflowBox should usually be wrapped
|
||||
/// in a RenderClipRect.
|
||||
///
|
||||
/// The child is positioned at the top left of the box. To position a smaller
|
||||
/// child inside a larger parent, use [RenderPositionedBox] and
|
||||
/// [RenderConstrainedBox] rather than RenderOverflowBox.
|
||||
///
|
||||
/// If you pass null for innerWidth or innerHeight, the constraints from the
|
||||
/// parent are passed instead.
|
||||
class RenderOverflowBox extends RenderProxyBox {
|
||||
RenderOverflowBox({
|
||||
RenderBox child,
|
||||
double innerWidth,
|
||||
double innerHeight
|
||||
}) : _innerWidth = innerWidth, _innerHeight = innerHeight, super(child);
|
||||
|
||||
/// The tight width constraint to give the child. Set this to null (the
|
||||
/// default) to use the constraints from the parent instead.
|
||||
double get innerWidth => _innerWidth;
|
||||
double _innerWidth;
|
||||
void set innerWidth (double value) {
|
||||
if (_innerWidth == value)
|
||||
return;
|
||||
_innerWidth = value;
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
/// The tight height constraint to give the child. Set this to null (the
|
||||
/// default) to use the constraints from the parent instead.
|
||||
double get innerHeight => _innerHeight;
|
||||
double _innerHeight;
|
||||
void set innerHeight (double value) {
|
||||
if (_innerHeight == value)
|
||||
return;
|
||||
_innerHeight = value;
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
BoxConstraints childConstraints(BoxConstraints constraints) {
|
||||
return new BoxConstraints(
|
||||
minWidth: _innerWidth ?? constraints.minWidth,
|
||||
maxWidth: _innerWidth ?? constraints.maxWidth,
|
||||
minHeight: _innerHeight ?? constraints.minHeight,
|
||||
maxHeight: _innerHeight ?? constraints.maxHeight
|
||||
);
|
||||
}
|
||||
|
||||
double getMinIntrinsicWidth(BoxConstraints constraints) {
|
||||
return constraints.constrainWidth();
|
||||
}
|
||||
|
||||
double getMaxIntrinsicWidth(BoxConstraints constraints) {
|
||||
return constraints.constrainWidth();
|
||||
}
|
||||
|
||||
double getMinIntrinsicHeight(BoxConstraints constraints) {
|
||||
return constraints.constrainHeight();
|
||||
}
|
||||
|
||||
double getMaxIntrinsicHeight(BoxConstraints constraints) {
|
||||
return constraints.constrainHeight();
|
||||
}
|
||||
|
||||
bool get sizedByParent => true;
|
||||
|
||||
void performResize() {
|
||||
size = constraints.biggest;
|
||||
}
|
||||
|
||||
void performLayout() {
|
||||
if (child != null)
|
||||
child.layout(childConstraints(constraints));
|
||||
}
|
||||
|
||||
String debugDescribeSettings(String prefix) {
|
||||
return '${super.debugDescribeSettings(prefix)}' +
|
||||
'${prefix}innerWidth: ${innerWidth ?? "use parent width constraints"}\n' +
|
||||
'${prefix}innerHeight: ${innerHeight ?? "use parent height constraints"}\n';
|
||||
}
|
||||
}
|
||||
|
||||
/// Forces child to layout at a specific aspect ratio
|
||||
///
|
||||
/// The width of this render object is the largest width permited by the layout
|
||||
|
Loading…
x
Reference in New Issue
Block a user