| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 import '../animation/curves.dart'; | 5 import '../animation/curves.dart'; |
| 6 import '../animation/fling_curve.dart'; | 6 import '../animation/fling_curve.dart'; |
| 7 import '../animation/generator.dart'; | 7 import '../animation/generator.dart'; |
| 8 import '../animation/scroll_curve.dart'; | 8 import '../animation/scroll_curve.dart'; |
| 9 import '../animation/kinematics.dart'; |
| 10 import '../animation/simulation.dart'; |
| 9 import '../fn.dart'; | 11 import '../fn.dart'; |
| 10 import 'dart:sky' as sky; | 12 import 'dart:sky' as sky; |
| 11 | 13 |
| 12 abstract class Scrollable extends Component { | 14 abstract class Scrollable extends Component { |
| 13 ScrollCurve scrollCurve; | 15 ScrollCurve scrollCurve; |
| 14 double get scrollOffset => _scrollOffset; | 16 double get scrollOffset => _scrollOffset; |
| 15 | 17 |
| 16 double _scrollOffset = 0.0; | 18 double _scrollOffset = 0.0; |
| 17 FlingCurve _flingCurve; | 19 FlingCurve _flingCurve; |
| 18 int _flingAnimationId; | 20 int _flingAnimationId; |
| 19 AnimationGenerator _scrollAnimation; | 21 Simulation _simulation; |
| 20 | 22 |
| 21 Scrollable({Object key, this.scrollCurve}) : super(key: key) { | 23 Scrollable({Object key, this.scrollCurve}) : super(key: key) { |
| 22 events.listen('pointerdown', _handlePointerDown); | 24 events.listen('pointerdown', _handlePointerDown); |
| 23 events.listen('pointerup', _handlePointerUpOrCancel); | 25 events.listen('pointerup', _handlePointerUpOrCancel); |
| 24 events.listen('pointercancel', _handlePointerUpOrCancel); | 26 events.listen('pointercancel', _handlePointerUpOrCancel); |
| 25 events.listen('gestureflingstart', _handleFlingStart); | 27 events.listen('gestureflingstart', _handleFlingStart); |
| 26 events.listen('gestureflingcancel', _handleFlingCancel); | 28 events.listen('gestureflingcancel', _handleFlingCancel); |
| 27 events.listen('gesturescrollupdate', _handleScrollUpdate); | 29 events.listen('gesturescrollupdate', _handleScrollUpdate); |
| 28 events.listen('wheel', _handleWheel); | 30 events.listen('wheel', _handleWheel); |
| 29 } | 31 } |
| 30 | 32 |
| 31 void didUnmount() { | 33 void didUnmount() { |
| 32 super.didUnmount(); | 34 super.didUnmount(); |
| 33 _stopFling(); | 35 _stopFling(); |
| 34 _stopScrollAnimation(); | 36 _stopSimulation(); |
| 35 } | 37 } |
| 36 | 38 |
| 37 bool scrollBy(double scrollDelta) { | 39 bool scrollBy(double scrollDelta) { |
| 38 var newScrollOffset = scrollCurve.apply(_scrollOffset, scrollDelta); | 40 var newScrollOffset = scrollCurve.apply(_scrollOffset, scrollDelta); |
| 39 if (newScrollOffset == _scrollOffset) | 41 if (newScrollOffset == _scrollOffset) |
| 40 return false; | 42 return false; |
| 41 setState(() { | 43 setState(() { |
| 42 _scrollOffset = newScrollOffset; | 44 _scrollOffset = newScrollOffset; |
| 43 }); | 45 }); |
| 44 return true; | 46 return true; |
| 45 } | 47 } |
| 46 | 48 |
| 47 void animateScrollTo(double targetScrollOffset, { | |
| 48 double initialDelay: 0.0, | |
| 49 double duration: 0.0, | |
| 50 Curve curve: linear}) { | |
| 51 _stopScrollAnimation(); | |
| 52 _scrollAnimation = new AnimationGenerator( | |
| 53 duration: duration, | |
| 54 begin: _scrollOffset, | |
| 55 end: targetScrollOffset, | |
| 56 initialDelay: initialDelay, | |
| 57 curve: curve); | |
| 58 _scrollAnimation.onTick.listen((newScrollOffset) { | |
| 59 if (!scrollBy(newScrollOffset - _scrollOffset)) | |
| 60 _stopScrollAnimation(); | |
| 61 }, onDone: () { | |
| 62 _scrollAnimation = null; | |
| 63 }); | |
| 64 } | |
| 65 | |
| 66 void _scheduleFlingUpdate() { | 49 void _scheduleFlingUpdate() { |
| 67 _flingAnimationId = sky.window.requestAnimationFrame(_updateFling); | 50 _flingAnimationId = sky.window.requestAnimationFrame(_updateFling); |
| 68 } | 51 } |
| 69 | 52 |
| 70 void _stopFling() { | 53 void _stopFling() { |
| 71 if (_flingAnimationId == null) | 54 if (_flingAnimationId == null) |
| 72 return; | 55 return; |
| 73 sky.window.cancelAnimationFrame(_flingAnimationId); | 56 sky.window.cancelAnimationFrame(_flingAnimationId); |
| 74 _flingCurve = null; | 57 _flingCurve = null; |
| 75 _flingAnimationId = null; | 58 _flingAnimationId = null; |
| 76 } | 59 } |
| 77 | 60 |
| 78 void _stopScrollAnimation() { | 61 void _stopSimulation() { |
| 79 if (_scrollAnimation == null) | 62 if (_simulation == null) |
| 80 return; | 63 return; |
| 81 _scrollAnimation.cancel(); | 64 _simulation.cancel(); |
| 82 _scrollAnimation = null; | 65 _simulation = null; |
| 83 } | 66 } |
| 84 | 67 |
| 85 void _updateFling(double timeStamp) { | 68 void _updateFling(double timeStamp) { |
| 86 double scrollDelta = _flingCurve.update(timeStamp); | 69 double scrollDelta = _flingCurve.update(timeStamp); |
| 87 if (!scrollBy(scrollDelta)) | 70 if (!scrollBy(scrollDelta)) |
| 88 return _settle(); | 71 return _settle(); |
| 89 _scheduleFlingUpdate(); | 72 _scheduleFlingUpdate(); |
| 90 } | 73 } |
| 91 | 74 |
| 92 void _settle() { | 75 void _settle() { |
| 93 _stopFling(); | 76 _stopFling(); |
| 94 if (_scrollOffset < 0.0) | 77 Particle particle = new Particle(position: scrollOffset); |
| 95 animateScrollTo(0.0, duration: 200.0, curve: easeOut); | 78 _simulation = scrollCurve.release(particle); |
| 79 if (_simulation == null) |
| 80 return; |
| 81 _simulation.onTick.listen((_) { |
| 82 setState(() { |
| 83 _scrollOffset = particle.position; |
| 84 }); |
| 85 }); |
| 96 } | 86 } |
| 97 | 87 |
| 98 void _handlePointerDown(_) { | 88 void _handlePointerDown(_) { |
| 99 _stopFling(); | 89 _stopFling(); |
| 100 _stopScrollAnimation(); | 90 _stopSimulation(); |
| 101 } | 91 } |
| 102 | 92 |
| 103 void _handlePointerUpOrCancel(_) { | 93 void _handlePointerUpOrCancel(_) { |
| 104 if (_flingCurve == null) | 94 if (_flingCurve == null) |
| 105 _settle(); | 95 _settle(); |
| 106 } | 96 } |
| 107 | 97 |
| 108 void _handleScrollUpdate(sky.GestureEvent event) { | 98 void _handleScrollUpdate(sky.GestureEvent event) { |
| 109 scrollBy(-event.dy); | 99 scrollBy(-event.dy); |
| 110 } | 100 } |
| 111 | 101 |
| 112 void _handleFlingStart(sky.GestureEvent event) { | 102 void _handleFlingStart(sky.GestureEvent event) { |
| 113 _stopScrollAnimation(); | 103 _stopSimulation(); |
| 114 _flingCurve = new FlingCurve(-event.velocityY, event.timeStamp); | 104 _flingCurve = new FlingCurve(-event.velocityY, event.timeStamp); |
| 115 _scheduleFlingUpdate(); | 105 _scheduleFlingUpdate(); |
| 116 } | 106 } |
| 117 | 107 |
| 118 void _handleFlingCancel(sky.GestureEvent event) { | 108 void _handleFlingCancel(sky.GestureEvent event) { |
| 119 _settle(); | 109 _settle(); |
| 120 } | 110 } |
| 121 | 111 |
| 122 void _handleWheel(sky.WheelEvent event) { | 112 void _handleWheel(sky.WheelEvent event) { |
| 123 scrollBy(-event.offsetY); | 113 scrollBy(-event.offsetY); |
| 124 } | 114 } |
| 125 } | 115 } |
| OLD | NEW |