Commit 6128f48c authored by Adam Barth's avatar Adam Barth Committed by GitHub

Switch SlideTransition over to using Offset (#12369)

Previously, we used `Alignment`, which was difficult to understand. Now,
we just use an `Offset` scaled to the child's size, which is much easier
to understand.
parent 31b6ac04
......@@ -47,9 +47,9 @@ class NavigationIconView {
return new FadeTransition(
opacity: _animation,
child: new SlideTransition(
position: new AlignmentTween(
begin: const Alignment(0.0, 0.4), // Slightly down.
end: Alignment.center,
position: new Tween<Offset>(
begin: const Offset(0.0, 0.02), // Slightly down.
end: Offset.zero,
).animate(_animation),
child: new IconTheme(
data: new IconThemeData(
......
......@@ -25,7 +25,7 @@ class _DrawerDemoState extends State<DrawerDemo> with TickerProviderStateMixin {
AnimationController _controller;
Animation<double> _drawerContentsOpacity;
Animation<Alignment> _drawerDetailsPosition;
Animation<Offset> _drawerDetailsPosition;
bool _showDrawerContents = true;
@override
......@@ -39,9 +39,9 @@ class _DrawerDemoState extends State<DrawerDemo> with TickerProviderStateMixin {
parent: new ReverseAnimation(_controller),
curve: Curves.fastOutSlowIn,
);
_drawerDetailsPosition = new AlignmentTween(
begin: const Alignment(0.0, -2.0),
end: Alignment.center,
_drawerDetailsPosition = new Tween<Offset>(
begin: const Offset(0.0, -1.0),
end: Offset.zero,
).animate(new CurvedAnimation(
parent: _controller,
curve: Curves.fastOutSlowIn,
......
......@@ -10,22 +10,22 @@ import 'package:flutter/widgets.dart';
const double _kBackGestureWidth = 20.0;
const double _kMinFlingVelocity = 1.0; // Screen widths per second.
// Fractional offset from offscreen to the right to fully on screen.
final AlignmentTween _kRightMiddleTween = new AlignmentTween(
begin: Alignment.centerRight * 2.0,
end: Alignment.center,
// Offset from offscreen to the right to fully on screen.
final Tween<Offset> _kRightMiddleTween = new Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
);
// Fractional offset from fully on screen to 1/3 offscreen to the left.
final AlignmentTween _kMiddleLeftTween = new AlignmentTween(
begin: Alignment.center,
end: const Alignment(-2.0/3.0, 0.0),
// Offset from fully on screen to 1/3 offscreen to the left.
final Tween<Offset> _kMiddleLeftTween = new Tween<Offset>(
begin: Offset.zero,
end: const Offset(-1.0/3.0, 0.0),
);
// Fractional offset from offscreen below to fully on screen.
final AlignmentTween _kBottomUpTween = new AlignmentTween(
begin: Alignment.bottomCenter * 2.0,
end: Alignment.center,
// Offset from offscreen below to fully on screen.
final Tween<Offset> _kBottomUpTween = new Tween<Offset>(
begin: const Offset(0.0, 1.0),
end: Offset.zero,
);
// Custom decoration from no shadow to page shadow mimicking iOS page
......@@ -318,9 +318,9 @@ class CupertinoPageTransition extends StatelessWidget {
super(key: key);
// When this page is coming in to cover another page.
final Animation<Alignment> _primaryPositionAnimation;
final Animation<Offset> _primaryPositionAnimation;
// When this page is becoming covered by another page.
final Animation<Alignment> _secondaryPositionAnimation;
final Animation<Offset> _secondaryPositionAnimation;
final Animation<Decoration> _primaryShadowAnimation;
/// The widget below this widget in the tree.
......@@ -361,7 +361,7 @@ class CupertinoFullscreenDialogTransition extends StatelessWidget {
),
super(key: key);
final Animation<Alignment> _positionAnimation;
final Animation<Offset> _positionAnimation;
/// The widget below this widget in the tree.
final Widget child;
......
......@@ -9,9 +9,9 @@ import 'package:flutter/widgets.dart';
import 'theme.dart';
// Fractional offset from 1/4 screen below the top to fully on screen.
final AlignmentTween _kBottomUpTween = new AlignmentTween(
begin: Alignment.bottomCenter * 0.5,
end: Alignment.center
final Tween<Offset> _kBottomUpTween = new Tween<Offset>(
begin: const Offset(0.0, 0.25),
end: Offset.zero,
);
// Used for Android and Fuchsia.
......@@ -26,7 +26,7 @@ class _MountainViewPageTransition extends StatelessWidget {
)),
super(key: key);
final Animation<Alignment> _positionAnimation;
final Animation<Offset> _positionAnimation;
final Widget child;
@override
......
......@@ -1896,27 +1896,33 @@ class RenderFittedBox extends RenderProxyBox {
/// Applies a translation transformation before painting its child.
///
/// The translation is expressed as a [Alignment] relative to the
/// RenderFractionalTranslation box's size. Hit tests will only be detected
/// inside the bounds of the RenderFractionalTranslation, even if the contents
/// are offset such that they overflow.
/// The translation is expressed as a [Offset] scaled to the child's size. For
/// example, an [Offset] with a `dx` of 0.25 will result in a horizontal
/// translation of one quarter the width of the child.
///
/// Hit tests will only be detected inside the bounds of the
/// [RenderFractionalTranslation], even if the contents are offset such that
/// they overflow.
class RenderFractionalTranslation extends RenderProxyBox {
/// Creates a render object that translates its child's painting.
///
/// The [translation] argument must not be null.
RenderFractionalTranslation({
Alignment translation,
@required Offset translation,
this.transformHitTests: true,
RenderBox child
}) : assert(translation == null || (translation.x != null && translation.y != null)),
}) : assert(translation != null),
_translation = translation,
super(child);
/// The translation to apply to the child, relative to the child's center.
Alignment get translation => _translation;
Alignment _translation;
set translation(Alignment value) {
assert(value == null || (value.x != null && value.y != null));
/// The translation to apply to the child, scaled to the child's size.
///
/// For example, an [Offset] with a `dx` of 0.25 will result in a horizontal
/// translation of one quarter the width of the child.
Offset get translation => _translation;
Offset _translation;
set translation(Offset value) {
assert(value != null);
if (_translation == value)
return;
_translation = value;
......@@ -1935,11 +1941,9 @@ class RenderFractionalTranslation extends RenderProxyBox {
bool hitTest(HitTestResult result, { Offset position }) {
assert(!debugNeedsLayout);
if (transformHitTests) {
final double halfWidth = size.width / 2.0;
final double halfHeight = size.height / 2.0;
position = new Offset(
position.dx - translation.x * halfWidth,
position.dy - translation.y * halfHeight,
position.dx - translation.dx * size.width,
position.dy - translation.dy * size.height,
);
}
return super.hitTest(result, position: position);
......@@ -1949,26 +1953,25 @@ class RenderFractionalTranslation extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) {
assert(!debugNeedsLayout);
if (child != null) {
final double halfWidth = size.width / 2.0;
final double halfHeight = size.height / 2.0;
super.paint(context, new Offset(
offset.dx + translation.x * halfWidth,
offset.dy + translation.y * halfHeight,
offset.dx + translation.dx * size.width,
offset.dy + translation.dy * size.height,
));
}
}
@override
void applyPaintTransform(RenderBox child, Matrix4 transform) {
final double halfWidth = size.width / 2.0;
final double halfHeight = size.height / 2.0;
transform.translate(translation.x * halfWidth, translation.y * halfHeight);
transform.translate(
translation.dx * size.width,
translation.dy * size.height,
);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder description) {
super.debugFillProperties(description);
description.add(new DiagnosticsProperty<Alignment>('translation', translation));
description.add(new DiagnosticsProperty<Offset>('translation', translation));
description.add(new DiagnosticsProperty<bool>('transformHitTests', transformHitTests));
}
}
......
......@@ -987,8 +987,15 @@ class FittedBox extends SingleChildRenderObjectWidget {
}
}
/// A widget that applies a translation expressed as a fraction of the box's
/// size before painting its child.
/// Applies a translation transformation before painting its child.
///
/// The translation is expressed as a [Offset] scaled to the child's size. For
/// example, an [Offset] with a `dx` of 0.25 will result in a horizontal
/// translation of one quarter the width of the child.
///
/// Hit tests will only be detected inside the bounds of the
/// [FractionalTranslation], even if the contents are offset such that
/// they overflow.
class FractionalTranslation extends SingleChildRenderObjectWidget {
/// Creates a widget that translates its child's painting.
///
......@@ -1001,8 +1008,11 @@ class FractionalTranslation extends SingleChildRenderObjectWidget {
}) : assert(translation != null),
super(key: key, child: child);
/// The translation to apply to the child, relative to the child's center.
final Alignment translation;
/// The translation to apply to the child, scaled to the child's size.
///
/// For example, an [Offset] with a `dx` of 0.25 will result in a horizontal
/// translation of one quarter the width of the child.
final Offset translation;
/// Whether to apply the translation when performing hit tests.
final bool transformHitTests;
......
......@@ -135,21 +135,19 @@ class _DismissibleClipper extends CustomClipper<Rect> {
super(reclip: moveAnimation);
final Axis axis;
final Animation<Alignment> moveAnimation;
final Animation<Offset> moveAnimation;
@override
Rect getClip(Size size) {
assert(axis != null);
switch (axis) {
case Axis.horizontal:
final double halfWidth = size.width / 2.0;
final double offset = halfWidth + moveAnimation.value.x * halfWidth;
final double offset = moveAnimation.value.dx * size.width;
if (offset < 0)
return new Rect.fromLTRB(size.width + offset, 0.0, size.width, size.height);
return new Rect.fromLTRB(0.0, 0.0, offset, size.height);
case Axis.vertical:
final double halfHeight = size.height / 2.0;
final double offset = halfHeight + moveAnimation.value.y * halfHeight;
final double offset = moveAnimation.value.dy * size.height;
if (offset < 0)
return new Rect.fromLTRB(0.0, size.height + offset, size.width, size.height);
return new Rect.fromLTRB(0.0, 0.0, size.width, offset);
......@@ -177,7 +175,7 @@ class _DismissibleState extends State<Dismissible> with TickerProviderStateMixin
}
AnimationController _moveController;
Animation<Alignment> _moveAnimation;
Animation<Offset> _moveAnimation;
AnimationController _resizeController;
Animation<double> _resizeAnimation;
......@@ -270,10 +268,10 @@ class _DismissibleState extends State<Dismissible> with TickerProviderStateMixin
}
void _updateMoveAnimation() {
final double end = _dragExtent.sign * 2.0;
_moveAnimation = new AlignmentTween(
begin: Alignment.center,
end: _directionIsXAxis ? new Alignment(end, 0.0) : new Alignment(0.0, end),
final double end = _dragExtent.sign;
_moveAnimation = new Tween<Offset>(
begin: Offset.zero,
end: _directionIsXAxis ? new Offset(end, 0.0) : new Offset(0.0, end),
).animate(_moveController);
}
......
......@@ -632,9 +632,9 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// Widget child,
/// ) {
/// return new SlideTransition(
/// position: new AlignmentTween(
/// begin: Alignment.bottomCenter,
/// end: Alignment.topCenter,
/// position: new Tween<Offset>(
/// begin: const Offset(0.0, 1.0),
/// end: Offset.zero,
/// ).animate(animation),
/// child: child, // child is the value returned by pageBuilder
/// );
......@@ -670,13 +670,13 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// ) {
/// return new SlideTransition(
/// position: new AlignmentTween(
/// begin: Alignment.bottomCenter,
/// end: Alignment.topCenter,
/// begin: const Offset(0.0, 1.0),
/// end: Offset.zero,
/// ).animate(animation),
/// child: new SlideTransition(
/// position: new AlignmentTween(
/// begin: Alignment.topCenter,
/// end: Alignment.bottomCenter,
/// position: new TweenOffset(
/// begin: Offset.zero,
/// end: const Offset(0.0, 1.0),
/// ).animate(secondaryAnimation),
/// child: child,
/// ),
......
......@@ -97,22 +97,28 @@ class _AnimatedState extends State<AnimatedWidget> {
}
/// Animates the position of a widget relative to its normal position.
///
/// The translation is expressed as a [Offset] scaled to the child's size. For
/// example, an [Offset] with a `dx` of 0.25 will result in a horizontal
/// translation of one quarter the width of the child.
class SlideTransition extends AnimatedWidget {
/// Creates a fractional translation transition.
///
/// The [position] argument must not be null.
const SlideTransition({
Key key,
@required Animation<Alignment> position,
@required Animation<Offset> position,
this.transformHitTests: true,
this.child,
}) : super(key: key, listenable: position);
}) : assert(position != null),
super(key: key, listenable: position);
/// The animation that controls the position of the child.
///
/// If the current value of the position animation is (dx, dy), the child will
/// be translated horizontally by width * dx and vertically by height * dy.
Animation<Alignment> get position => listenable;
/// If the current value of the position animation is `(dx, dy)`, the child
/// will be translated horizontally by `width * dx` and vertically by
/// `height * dy`.
Animation<Offset> get position => listenable;
/// Whether hit testing should be affected by the slide animation.
///
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment