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

Side by Side Diff: sky/sdk/example/widgets/card_collection.dart

Issue 1227963003: Card "swipe-away" dismiss version 3: Uses BlockViewport (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Updated per review feedback Created 5 years, 5 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 | « no previous file | sky/sdk/lib/widgets/block_viewport.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 'dart:sky' as sky; 5 import 'dart:sky' as sky;
6 6
7 import 'package:vector_math/vector_math.dart'; 7 import 'package:vector_math/vector_math.dart';
8 import 'package:sky/animation/animation_performance.dart'; 8 import 'package:sky/animation/animation_performance.dart';
9 import 'package:sky/animation/scroll_behavior.dart';
9 import 'package:sky/base/lerp.dart'; 10 import 'package:sky/base/lerp.dart';
10 import 'package:sky/painting/text_style.dart'; 11 import 'package:sky/painting/text_style.dart';
11 import 'package:sky/theme/colors.dart'; 12 import 'package:sky/theme/colors.dart';
12 import 'package:sky/widgets/animated_container.dart'; 13 import 'package:sky/widgets/animated_container.dart';
13 import 'package:sky/widgets/basic.dart'; 14 import 'package:sky/widgets/basic.dart';
15 import 'package:sky/widgets/block_viewport.dart';
14 import 'package:sky/widgets/card.dart'; 16 import 'package:sky/widgets/card.dart';
15 import 'package:sky/widgets/scaffold.dart'; 17 import 'package:sky/widgets/scaffold.dart';
18 import 'package:sky/widgets/scrollable.dart';
16 import 'package:sky/widgets/theme.dart'; 19 import 'package:sky/widgets/theme.dart';
17 import 'package:sky/widgets/tool_bar.dart'; 20 import 'package:sky/widgets/tool_bar.dart';
18 import 'package:sky/widgets/widget.dart'; 21 import 'package:sky/widgets/widget.dart';
19 22
20 23
21 const int _kCardDismissFadeoutMS = 300; 24 const int _kCardDismissFadeoutMS = 300;
22 const double _kMinCardFlingVelocity = 0.4; 25 const double _kMinFlingVelocity = 700.0;
23 const double _kDismissCardThreshold = 0.70; 26 const double _kMinFlingVelocityDelta = 400.0;
27 const double _kDismissCardThreshold = 0.6;
28
29 class VariableHeightScrollable extends Scrollable {
30 VariableHeightScrollable({
31 String key,
32 this.builder,
33 this.token
34 }) : super(key: key);
35
36 IndexedBuilder builder;
37 Object token;
38
39 void syncFields(VariableHeightScrollable source) {
40 builder = source.builder;
41 token = source.token;
42 super.syncFields(source);
43 }
44
45 ScrollBehavior createScrollBehavior() => new OverscrollBehavior();
46 OverscrollBehavior get scrollBehavior => super.scrollBehavior;
47
48 void _handleSizeChanged(Size newSize) {
49 setState(() {
50 scrollBehavior.containerHeight = newSize.height;
51 scrollBehavior.contentsHeight = 5000.0;
52 });
53 }
54
55 Widget buildContent() {
56 return new SizeObserver(
57 callback: _handleSizeChanged,
58 child: new BlockViewport(
59 builder: builder,
60 startOffset: scrollOffset,
61 token: token
62 )
63 );
64 }
65 }
24 66
25 class CardCollectionApp extends App { 67 class CardCollectionApp extends App {
26 68
27 final TextStyle cardLabelStyle = 69 final TextStyle cardLabelStyle =
28 new TextStyle(color: White, fontSize: 18.0, fontWeight: bold); 70 new TextStyle(color: White, fontSize: 18.0, fontWeight: bold);
29 71
72 final List<double> cardHeights = [
73 48.0, 64.0, 82.0, 46.0, 60.0, 55.0, 84.0, 96.0, 50.0,
74 48.0, 64.0, 82.0, 46.0, 60.0, 55.0, 84.0, 96.0, 50.0,
75 48.0, 64.0, 82.0, 46.0, 60.0, 55.0, 84.0, 96.0, 50.0
76 ];
77
78 List<int> visibleCardIndices;
79
30 CardCollectionApp() { 80 CardCollectionApp() {
31 _activeCardTransform = new AnimatedContainer() 81 _activeCardTransform = new AnimatedContainer()
32 ..position = new AnimatedType<Point>(Point.origin) 82 ..position = new AnimatedType<Point>(Point.origin)
33 ..opacity = new AnimatedType<double>(1.0, end: 0.0); 83 ..opacity = new AnimatedType<double>(1.0, end: 0.0);
84
34 _activeCardAnimation = _activeCardTransform.createPerformance( 85 _activeCardAnimation = _activeCardTransform.createPerformance(
35 [_activeCardTransform.position, _activeCardTransform.opacity], 86 [_activeCardTransform.position, _activeCardTransform.opacity],
36 duration: new Duration(milliseconds: _kCardDismissFadeoutMS)); 87 duration: new Duration(milliseconds: _kCardDismissFadeoutMS));
37 _activeCardAnimation.addListener(_handleAnimationProgressChanged); 88 _activeCardAnimation.addListener(_handleAnimationProgressChanged);
89
90 visibleCardIndices = new List.generate(cardHeights.length, (i) => i);
38 } 91 }
39 92
40 int _activeCardIndex = -1; 93 int _activeCardIndex = -1;
41 AnimatedContainer _activeCardTransform; 94 AnimatedContainer _activeCardTransform;
42 AnimationPerformance _activeCardAnimation; 95 AnimationPerformance _activeCardAnimation;
43 double _activeCardWidth; 96 double _activeCardWidth;
44 double _activeCardDragX = 0.0; 97 double _activeCardDragX = 0.0;
45 bool _activeCardDragUnderway = false; 98 bool _activeCardDragUnderway = false;
46 Set<int> _dismissedCardIndices = new Set<int>();
47 99
48 Point get _activeCardDragEndPoint { 100 Point get _activeCardDragEndPoint {
49 return new Point(_activeCardDragX.sign * _activeCardWidth * _kDismissCardThr eshold, 0.0); 101 return new Point(_activeCardDragX.sign * _activeCardWidth * _kDismissCardThr eshold, 0.0);
50 } 102 }
51 103
52 void _handleAnimationProgressChanged() { 104 void _handleAnimationProgressChanged() {
53 setState(() { 105 setState(() {
54 if (_activeCardAnimation.isCompleted && !_activeCardDragUnderway) 106 if (_activeCardAnimation.isCompleted && !_activeCardDragUnderway)
55 _dismissedCardIndices.add(_activeCardIndex); 107 visibleCardIndices.remove(_activeCardIndex);
56 }); 108 });
57 } 109 }
58 110
59 void _handleSizeChanged(Size newSize) { 111 void _handleSizeChanged(Size newSize) {
60 _activeCardWidth = newSize.width; 112 _activeCardWidth = newSize.width;
61 _activeCardTransform.position.end = _activeCardDragEndPoint; 113 _activeCardTransform.position.end = _activeCardDragEndPoint;
62 } 114 }
63 115
64 void _handlePointerDown(sky.PointerEvent event, int cardIndex) { 116 void _handlePointerDown(sky.PointerEvent event, int cardIndex) {
65 setState(() { 117 setState(() {
(...skipping 19 matching lines...) Expand all
85 }); 137 });
86 } 138 }
87 139
88 void _handlePointerUpOrCancel(_) { 140 void _handlePointerUpOrCancel(_) {
89 if (_activeCardWidth == null || _activeCardIndex < 0) 141 if (_activeCardWidth == null || _activeCardIndex < 0)
90 return; 142 return;
91 143
92 setState(() { 144 setState(() {
93 _activeCardDragUnderway = false; 145 _activeCardDragUnderway = false;
94 if (_activeCardAnimation.isCompleted) 146 if (_activeCardAnimation.isCompleted)
95 _dismissedCardIndices.add(_activeCardIndex); 147 visibleCardIndices.remove(_activeCardIndex);
96 else if (!_activeCardAnimation.isAnimating) 148 else if (!_activeCardAnimation.isAnimating)
97 _activeCardAnimation.progress = 0.0; 149 _activeCardAnimation.progress = 0.0;
98 }); 150 });
99 } 151 }
100 152
153 bool _isHorizontalFlingGesture(sky.GestureEvent event) {
154 double vx = event.velocityX.abs();
155 double vy = event.velocityY.abs();
156 return vx - vy > _kMinFlingVelocityDelta && vx > _kMinFlingVelocity;
157 }
158
101 void _handleFlingStart(sky.GestureEvent event) { 159 void _handleFlingStart(sky.GestureEvent event) {
102 if (_activeCardWidth == null || _activeCardIndex < 0) 160 if (_activeCardWidth == null || _activeCardIndex < 0)
103 return; 161 return;
104 162
105 _activeCardDragUnderway = false; 163 _activeCardDragUnderway = false;
106 double velocityX = event.velocityX / 1000; 164
107 if (velocityX.abs() >= _kMinCardFlingVelocity) { 165 if (_isHorizontalFlingGesture(event)) {
108 double distance = 1.0 - _activeCardAnimation.progress; 166 double distance = 1.0 - _activeCardAnimation.progress;
109 if (distance > 0.0) { 167 if (distance > 0.0) {
110 double duration = 150.0 * distance / velocityX.abs(); 168 double duration = 250.0 * 1000.0 * distance / event.velocityX.abs();
111 _activeCardDragX = velocityX.sign; 169 _activeCardDragX = event.velocityX.sign;
112 _activeCardAnimation.timeline.animateTo(1.0, duration: duration); 170 _activeCardAnimation.timeline.animateTo(1.0, duration: duration);
113 } 171 }
114 } 172 }
115 } 173 }
116 174
117 Widget _buildCard(int index, Color color) { 175 Widget _buildCard(int cardIndex) {
118 Widget label = new Center(child: new Text("Item ${index}", style: cardLabelS tyle)); 176 Widget label = new Center(child: new Text("Item ${cardIndex}", style: cardLa belStyle));
177 Color color = lerpColor(Red[500], Blue[500], cardIndex / cardHeights.length) ;
119 Widget card = new Card( 178 Widget card = new Card(
120 child: new Padding(child: label, padding: const EdgeDims.all(8.0)), 179 child: new Padding(child: label, padding: const EdgeDims.all(8.0)),
121 color: color 180 color: color
122 ); 181 );
123 182
124 // TODO(hansmuller) The code below changes the card's widget tree when 183 // TODO(hansmuller) The code below changes the card's widget tree when
125 // the user starts dragging it. Currently this causes Sky to drop the 184 // the user starts dragging it. Currently this causes Sky to drop the
126 // rest of the pointer gesture, see https://github.com/domokit/mojo/issues/3 12. 185 // rest of the pointer gesture, see https://github.com/domokit/mojo/issues/3 12.
127 // As a workaround, always create the Transform and Opacity nodes. 186 // As a workaround, always create the Transform and Opacity nodes.
128 if (index == _activeCardIndex) { 187 if (cardIndex == _activeCardIndex) {
129 card = _activeCardTransform.build(card); 188 card = _activeCardTransform.build(card);
130 } else { 189 } else {
131 card = new Transform(child: card, transform: new Matrix4.identity()); 190 card = new Transform(child: card, transform: new Matrix4.identity());
132 card = new Opacity(child: card, opacity: 1.0); 191 card = new Opacity(child: card, opacity: 1.0);
133 } 192 }
134 193
135 return new Listener( 194 return new Listener(
136 child: card, 195 key: "$cardIndex",
137 onPointerDown: (event) { _handlePointerDown(event, index); }, 196 child: new Container(child: card, height: cardHeights[cardIndex]),
197 onPointerDown: (event) { _handlePointerDown(event, cardIndex); },
138 onPointerMove: _handlePointerMove, 198 onPointerMove: _handlePointerMove,
139 onPointerUp: _handlePointerUpOrCancel, 199 onPointerUp: _handlePointerUpOrCancel,
140 onPointerCancel: _handlePointerUpOrCancel, 200 onPointerCancel: _handlePointerUpOrCancel,
141 onGestureFlingStart: _handleFlingStart 201 onGestureFlingStart: _handleFlingStart
142 ); 202 );
143 } 203 }
144 204
145 Widget _buildCardCollection(List<double> heights) { 205 Widget _builder(int index) {
146 List<Widget> items = <Widget>[]; 206 if (index >= visibleCardIndices.length)
147 for(int index = 0; index < heights.length; index++) { 207 return null;
148 if (_dismissedCardIndices.contains(index)) 208 return _buildCard(visibleCardIndices[index]);
149 continue;
150 Color color = lerpColor(Red[500], Blue[500], index / heights.length);
151 items.add(new Container(
152 child: _buildCard(index, color),
153 height: heights[index]
154 ));
155 }
156
157 return new Container(
158 child: new SizeObserver(child: new Block(items), callback: _handleSizeChan ged),
159 padding: const EdgeDims.symmetric(vertical: 12.0, horizontal: 8.0),
160 decoration: new BoxDecoration(backgroundColor: Theme.of(this).primarySwatc h[50])
161 );
162 } 209 }
163 210
164 Widget build() { 211 Widget build() {
212 Widget cardCollection = new Container(
213 padding: const EdgeDims.symmetric(vertical: 12.0, horizontal: 8.0),
214 decoration: new BoxDecoration(backgroundColor: Theme.of(this).primarySwatc h[50]),
215 child: new VariableHeightScrollable(
216 builder: _builder,
217 token: visibleCardIndices.length
218 )
219 );
220
165 return new Scaffold( 221 return new Scaffold(
166 toolbar: new ToolBar(center: new Text('Swipe Away')), 222 toolbar: new ToolBar(center: new Text('Swipe Away')),
167 body: _buildCardCollection( 223 body: new SizeObserver(child: cardCollection, callback: _handleSizeChanged )
168 [48.0, 64.0, 82.0, 46.0, 60.0, 55.0, 84.0, 96.0, 50.0,
169 48.0, 64.0, 82.0, 46.0, 60.0, 55.0, 84.0, 96.0, 50.0])
170 ); 224 );
171 } 225 }
172 } 226 }
173 227
174 void main() { 228 void main() {
175 runApp(new CardCollectionApp()); 229 runApp(new CardCollectionApp());
176 } 230 }
OLDNEW
« no previous file with comments | « no previous file | sky/sdk/lib/widgets/block_viewport.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698