mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Scrollable should settle back to 0.0
This CL teaches Scrollable how to settle back to a scroll offset of 0.0 after a fling or a scroll. There's still some room for improvement: 1) Some of this logic should be factored out into the scroll curve object. 2) We don't produce the correct animation curves when we fling into the overscroll region because we wait for the fling velocity to reach zero before we start the settling animation. R=ojan@chromium.org, eseidel@chromium.org Review URL: https://codereview.chromium.org/1005753002
This commit is contained in:
parent
52d2d67754
commit
70aa7795c7
@ -61,14 +61,15 @@ class AnimationGenerator extends FrameGenerator {
|
||||
Stream<double> _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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user