Adam Barth 85d02799fd Improve Sky's Scrollable physics
We now use a physics simulationt to drive the scroll fling. We're also closer
to integrating fling into overscroll.

R=eseidel@chromium.org

Review URL: https://codereview.chromium.org/1004363002
2015-03-13 15:57:41 -07:00

100 lines
2.7 KiB
Dart

// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import '../animation/generators.dart';
import '../animation/mechanics.dart';
import '../animation/scroll_behavior.dart';
import '../fn.dart';
import '../theme/view-configuration.dart' as config;
import 'dart:math' as math;
import 'dart:sky' as sky;
const double _kMillisecondsPerSecond = 1000.0;
double _velocityForFlingGesture(sky.GestureEvent event) {
return math.max(-config.kMaxFlingVelocity, math.min(config.kMaxFlingVelocity,
-event.velocityY)) / _kMillisecondsPerSecond;
}
abstract class Scrollable extends Component {
ScrollBehavior scrollBehavior;
double get scrollOffset => _scrollOffset;
double _scrollOffset = 0.0;
Simulation _simulation;
Scrollable({Object key, this.scrollBehavior}) : 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);
events.listen('wheel', _handleWheel);
}
void didUnmount() {
super.didUnmount();
_stopSimulation();
}
bool scrollBy(double scrollDelta) {
var newScrollOffset = scrollBehavior.applyCurve(_scrollOffset, scrollDelta);
if (newScrollOffset == _scrollOffset)
return false;
setState(() {
_scrollOffset = newScrollOffset;
});
return true;
}
void _stopSimulation() {
if (_simulation == null)
return;
_simulation.cancel();
_simulation = null;
}
void _startSimulation(Particle particle) {
_stopSimulation();
_simulation = scrollBehavior.release(particle);
if (_simulation == null)
return;
_simulation.onTick.listen((_) {
setState(() {
_scrollOffset = particle.position;
});
});
}
Particle _createParticle([double velocity = 0.0]) {
return new Particle(position: _scrollOffset, velocity: velocity);
}
void _handlePointerDown(_) {
_stopSimulation();
}
void _handlePointerUpOrCancel(_) {
if (_simulation == null)
_startSimulation(_createParticle());
}
void _handleScrollUpdate(sky.GestureEvent event) {
scrollBy(-event.dy);
}
void _handleFlingStart(sky.GestureEvent event) {
_startSimulation(_createParticle(_velocityForFlingGesture(event)));
}
void _handleFlingCancel(sky.GestureEvent event) {
_startSimulation(_createParticle());
}
void _handleWheel(sky.WheelEvent event) {
scrollBy(-event.offsetY);
}
}