Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(148)

Side by Side Diff: sky/framework/components/drawer.dart

Issue 1016093002: Begin work on the PopupMenu entrance animation (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sky/framework/animation/animation.dart ('k') | sky/framework/components/input.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/animation.dart'; 5 import '../animation/animated_value.dart';
6 import '../animation/curves.dart'; 6 import '../animation/curves.dart';
7 import '../fn.dart'; 7 import '../fn.dart';
8 import '../theme/colors.dart'; 8 import '../theme/colors.dart';
9 import '../theme/shadows.dart'; 9 import '../theme/shadows.dart';
10 import 'dart:async'; 10 import 'dart:async';
11 import 'dart:math' as math; 11 import 'dart:math' as math;
12 import 'dart:sky' as sky; 12 import 'dart:sky' as sky;
13 import 'material.dart'; 13 import 'material.dart';
14 14
15 const double _kWidth = 304.0; 15 const double _kWidth = 304.0;
16 const double _kMinFlingVelocity = 0.4; 16 const double _kMinFlingVelocity = 0.4;
17 const double _kBaseSettleDurationMS = 246.0; 17 const double _kBaseSettleDurationMS = 246.0;
18 const double _kMaxSettleDurationMS = 600.0; 18 const double _kMaxSettleDurationMS = 600.0;
19 const Curve _kAnimationCurve = parabolicRise; 19 const Curve _kAnimationCurve = parabolicRise;
20 20
21 class DrawerAnimation extends Animation { 21 class DrawerController {
22 Stream<double> get onPositionChanged => onValueChanged; 22 final AnimatedValue position = new AnimatedValue(-_kWidth);
23 23
24 bool get _isMostlyClosed => value <= -_kWidth / 2; 24 bool get _isMostlyClosed => position.value <= -_kWidth / 2;
25
26 DrawerAnimation() {
27 value = -_kWidth;
28 }
29 25
30 void toggle(_) => _isMostlyClosed ? _open() : _close(); 26 void toggle(_) => _isMostlyClosed ? _open() : _close();
31 27
32 void handleMaskTap(_) => _close(); 28 void handleMaskTap(_) => _close();
33 29
34 void handlePointerDown(_) => stop(); 30 void handlePointerDown(_) => position.stop();
35 31
36 void handlePointerMove(sky.PointerEvent event) { 32 void handlePointerMove(sky.PointerEvent event) {
37 if (isAnimating) 33 if (position.isAnimating)
38 return; 34 return;
39 value = math.min(0.0, math.max(value + event.dx, -_kWidth)); 35 position.value = math.min(0.0, math.max(position.value + event.dx, -_kWidth) );
40 } 36 }
41 37
42 void handlePointerUp(_) { 38 void handlePointerUp(_) {
43 if (!isAnimating) 39 if (!position.isAnimating)
44 _settle(); 40 _settle();
45 } 41 }
46 42
47 void handlePointerCancel(_) { 43 void handlePointerCancel(_) {
48 if (!isAnimating) 44 if (!position.isAnimating)
49 _settle(); 45 _settle();
50 } 46 }
51 47
52 void _open() => _animateToPosition(0.0); 48 void _open() => _animateToPosition(0.0);
53 49
54 void _close() => _animateToPosition(-_kWidth); 50 void _close() => _animateToPosition(-_kWidth);
55 51
56 void _settle() => _isMostlyClosed ? _close() : _open(); 52 void _settle() => _isMostlyClosed ? _close() : _open();
57 53
58 void _animateToPosition(double targetPosition) { 54 void _animateToPosition(double targetPosition) {
59 double distance = (targetPosition - value).abs(); 55 double distance = (targetPosition - position.value).abs();
60 if (distance != 0) { 56 if (distance != 0) {
61 double targetDuration = distance / _kWidth * _kBaseSettleDurationMS; 57 double targetDuration = distance / _kWidth * _kBaseSettleDurationMS;
62 double duration = math.min(targetDuration, _kMaxSettleDurationMS); 58 double duration = math.min(targetDuration, _kMaxSettleDurationMS);
63 animateTo(targetPosition, duration, curve: _kAnimationCurve); 59 position.animateTo(targetPosition, duration, curve: _kAnimationCurve);
64 } 60 }
65 } 61 }
66 62
67 void handleFlingStart(event) { 63 void handleFlingStart(event) {
68 double direction = event.velocityX.sign; 64 double direction = event.velocityX.sign;
69 double velocityX = event.velocityX.abs() / 1000; 65 double velocityX = event.velocityX.abs() / 1000;
70 if (velocityX < _kMinFlingVelocity) 66 if (velocityX < _kMinFlingVelocity)
71 return; 67 return;
72 68
73 double targetPosition = direction < 0.0 ? -_kWidth : 0.0; 69 double targetPosition = direction < 0.0 ? -_kWidth : 0.0;
74 double distance = (targetPosition - value).abs(); 70 double distance = (targetPosition - position.value).abs();
75 double duration = distance / velocityX; 71 double duration = distance / velocityX;
76 72
77 animateTo(targetPosition, duration, curve: linear); 73 position.animateTo(targetPosition, duration, curve: linear);
78 } 74 }
79 } 75 }
80 76
81 class Drawer extends Component { 77 class Drawer extends Component {
82 static final Style _style = new Style(''' 78 static final Style _style = new Style('''
83 position: absolute; 79 position: absolute;
84 top: 0; 80 top: 0;
85 left: 0; 81 left: 0;
86 bottom: 0; 82 bottom: 0;
87 right: 0;''' 83 right: 0;'''
88 ); 84 );
89 85
90 static final Style _maskStyle = new Style(''' 86 static final Style _maskStyle = new Style('''
91 background-color: black; 87 background-color: black;
92 will-change: opacity; 88 will-change: opacity;
93 position: absolute; 89 position: absolute;
94 top: 0; 90 top: 0;
95 left: 0; 91 left: 0;
96 bottom: 0; 92 bottom: 0;
97 right: 0;''' 93 right: 0;'''
98 ); 94 );
99 95
100 static final Style _contentStyle = new Style(''' 96 static final Style _contentStyle = new Style('''
101 background-color: ${Grey[50]}; 97 background-color: ${Grey[50]};
102 will-change: transform; 98 will-change: transform;
103 position: absolute; 99 position: absolute;
104 width: 304px; 100 width: ${_kWidth}px;
105 top: 0; 101 top: 0;
106 left: 0; 102 left: 0;
107 bottom: 0;''' 103 bottom: 0;'''
108 ); 104 );
109 105
110 DrawerAnimation animation;
111 List<Node> children; 106 List<Node> children;
112 int level; 107 int level;
108 DrawerController controller;
109
110 AnimatedValueListener _position;
113 111
114 Drawer({ 112 Drawer({
115 Object key, 113 Object key,
116 this.animation, 114 this.controller,
117 this.children, 115 this.children,
118 this.level: 0 116 this.level: 0
119 }) : super(key: key) { 117 }) : super(key: key) {
120 events.listen('pointerdown', animation.handlePointerDown); 118 events.listen('pointerdown', controller.handlePointerDown);
121 events.listen('pointermove', animation.handlePointerMove); 119 events.listen('pointermove', controller.handlePointerMove);
122 events.listen('pointerup', animation.handlePointerUp); 120 events.listen('pointerup', controller.handlePointerUp);
123 events.listen('pointercancel', animation.handlePointerCancel); 121 events.listen('pointercancel', controller.handlePointerCancel);
122 _position = new AnimatedValueListener(this, controller.position);
124 } 123 }
125 124
126 double _position = -_kWidth; 125 void didUnmount() {
127 126 _position.stopListening();
128 bool _listening = false;
129
130 void _ensureListening() {
131 if (_listening)
132 return;
133
134 _listening = true;
135 animation.onPositionChanged.listen((position) {
136 setState(() {
137 _position = position;
138 });
139 });
140 } 127 }
141 128
142 Node build() { 129 Node build() {
143 _ensureListening(); 130 _position.ensureListening();
144 131
145 bool isClosed = _position <= -_kWidth; 132 bool isClosed = _position.value <= -_kWidth;
146 String inlineStyle = 'display: ${isClosed ? 'none' : ''}'; 133 String inlineStyle = 'display: ${isClosed ? 'none' : ''}';
147 String maskInlineStyle = 'opacity: ${(_position / _kWidth + 1) * 0.5}'; 134 String maskInlineStyle = 'opacity: ${(_position.value / _kWidth + 1) * 0.5}' ;
148 String contentInlineStyle = 'transform: translateX(${_position}px)'; 135 String contentInlineStyle = 'transform: translateX(${_position.value}px)';
149 136
150 Container mask = new Container( 137 Container mask = new Container(
151 key: 'Mask', 138 key: 'Mask',
152 style: _maskStyle, 139 style: _maskStyle,
153 inlineStyle: maskInlineStyle 140 inlineStyle: maskInlineStyle
154 )..events.listen('gesturetap', animation.handleMaskTap) 141 )..events.listen('gesturetap', controller.handleMaskTap)
155 ..events.listen('gestureflingstart', animation.handleFlingStart); 142 ..events.listen('gestureflingstart', controller.handleFlingStart);
156 143
157 Material content = new Material( 144 Material content = new Material(
158 key: 'Content', 145 key: 'Content',
159 style: _contentStyle, 146 style: _contentStyle,
160 inlineStyle: contentInlineStyle, 147 inlineStyle: contentInlineStyle,
161 children: children, 148 children: children,
162 level: level 149 level: level
163 ); 150 );
164 151
165 return new Container( 152 return new Container(
166 style: _style, 153 style: _style,
167 inlineStyle: inlineStyle, 154 inlineStyle: inlineStyle,
168 children: [ mask, content ] 155 children: [ mask, content ]
169 ); 156 );
170 } 157 }
171 } 158 }
OLDNEW
« no previous file with comments | « sky/framework/animation/animation.dart ('k') | sky/framework/components/input.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698