diff --git a/framework/animation/generator.dart b/framework/animation/generator.dart index 65c373f548a7029301c7b55d5f3ece344a7b6236..065d1e5f65601bc8ebb36364f4b27f99529569fb 100644 --- a/framework/animation/generator.dart +++ b/framework/animation/generator.dart @@ -61,14 +61,15 @@ class AnimationGenerator extends FrameGenerator { Stream _stream; bool _done = false; - AnimationGenerator(this.duration, { + AnimationGenerator({ this.initialDelay: 0.0, + this.duration, this.begin: 0.0, this.end: 1.0, this.curve: linear, Function onDone }):super(onDone: onDone) { - assert(duration > 0); + assert(duration != null && duration > 0.0); double startTime = 0.0; _stream = super.onTick.map((timeStamp) { if (startTime == 0.0) @@ -132,8 +133,12 @@ class Animation { { Curve curve: linear, double initialDelay: 0.0 }) { stop(); - _animation = new AnimationGenerator(duration, begin: _value, end: newValue, - curve: curve, initialDelay: initialDelay); + _animation = new AnimationGenerator( + duration: duration, + begin: _value, + end: newValue, + curve: curve, + initialDelay: initialDelay); _animation.onTick.listen(_setValue, onDone: () { _animation = null; diff --git a/framework/components/ink_splash.dart b/framework/components/ink_splash.dart index a4c0a2587b481c6a98fa75796ef98e3754f20560..b31cc5f9d3bca1076b09a20b6b45fb4a77c58e3b 100644 --- a/framework/components/ink_splash.dart +++ b/framework/components/ink_splash.dart @@ -27,8 +27,11 @@ class SplashAnimation { : _offsetX = x - rect.left, _offsetY = y - rect.top { - _animation = new AnimationGenerator(_kSplashDuration, - end: _kSplashSize, curve: easeOut, onDone: onDone); + _animation = new AnimationGenerator( + duration:_kSplashDuration, + end: _kSplashSize, + curve: easeOut, + onDone: onDone); _styleChanged = _animation.onTick.map((p) => ''' top: ${_offsetY - p/2}px; diff --git a/framework/components/scrollable.dart b/framework/components/scrollable.dart index 20f285866ef2bc171fe1cec966d8b358b490f107..838dbe9c818d25c568c2632d29f3d281ddf53fe0 100644 --- a/framework/components/scrollable.dart +++ b/framework/components/scrollable.dart @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import '../animation/curves.dart'; import '../animation/fling_curve.dart'; +import '../animation/generator.dart'; import '../animation/scroll_curve.dart'; import '../fn.dart'; import 'dart:sky' as sky; @@ -14,8 +16,12 @@ abstract class Scrollable extends Component { double _scrollOffset = 0.0; FlingCurve _flingCurve; int _flingAnimationId; + AnimationGenerator _scrollAnimation; Scrollable({Object key, this.scrollCurve}) : super(key: key) { + events.listen('pointerdown', _handlePointerDown); + events.listen('pointerup', _handlePointerUpOrCancel); + events.listen('pointercancel', _handlePointerUpOrCancel); events.listen('gestureflingstart', _handleFlingStart); events.listen('gestureflingcancel', _handleFlingCancel); events.listen('gesturescrollupdate', _handleScrollUpdate); @@ -25,6 +31,7 @@ abstract class Scrollable extends Component { void didUnmount() { super.didUnmount(); _stopFling(); + _stopScrollAnimation(); } bool scrollBy(double scrollDelta) { @@ -37,6 +44,25 @@ abstract class Scrollable extends Component { return true; } + void animateScrollTo(double targetScrollOffset, { + double initialDelay: 0.0, + double duration: 0.0, + Curve curve: linear}) { + _stopScrollAnimation(); + _scrollAnimation = new AnimationGenerator( + duration: duration, + begin: _scrollOffset, + end: targetScrollOffset, + initialDelay: initialDelay, + curve: curve); + _scrollAnimation.onTick.listen((newScrollOffset) { + if (!scrollBy(newScrollOffset - _scrollOffset)) + _stopScrollAnimation(); + }, onDone: () { + _scrollAnimation = null; + }); + } + void _scheduleFlingUpdate() { _flingAnimationId = sky.window.requestAnimationFrame(_updateFling); } @@ -49,26 +75,48 @@ abstract class Scrollable extends Component { _flingAnimationId = null; } + void _stopScrollAnimation() { + if (_scrollAnimation == null) + return; + _scrollAnimation.cancel(); + _scrollAnimation = null; + } + void _updateFling(double timeStamp) { double scrollDelta = _flingCurve.update(timeStamp); if (!scrollBy(scrollDelta)) - return _stopFling(); + return _settle(); _scheduleFlingUpdate(); } + void _settle() { + _stopFling(); + if (_scrollOffset < 0.0) + animateScrollTo(0.0, duration: 200.0, curve: easeOut); + } + + void _handlePointerDown(_) { + _stopFling(); + _stopScrollAnimation(); + } + + void _handlePointerUpOrCancel(_) { + if (_flingCurve == null) + _settle(); + } + void _handleScrollUpdate(sky.GestureEvent event) { scrollBy(-event.dy); } void _handleFlingStart(sky.GestureEvent event) { - setState(() { - _flingCurve = new FlingCurve(-event.velocityY, event.timeStamp); - _scheduleFlingUpdate(); - }); + _stopScrollAnimation(); + _flingCurve = new FlingCurve(-event.velocityY, event.timeStamp); + _scheduleFlingUpdate(); } void _handleFlingCancel(sky.GestureEvent event) { - _stopFling(); + _settle(); } void _handleWheel(sky.WheelEvent event) {