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

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

Issue 1237713002: Dismissable component (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 | « sky/sdk/BUILD.gn ('k') | sky/sdk/lib/widgets/dismissable.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;
6
7 import 'package:vector_math/vector_math.dart';
8 import 'package:sky/animation/animation_performance.dart';
9 import 'package:sky/base/lerp.dart'; 5 import 'package:sky/base/lerp.dart';
10 import 'package:sky/painting/text_style.dart'; 6 import 'package:sky/painting/text_style.dart';
11 import 'package:sky/theme/colors.dart'; 7 import 'package:sky/theme/colors.dart';
12 import 'package:sky/widgets/animation_builder.dart';
13 import 'package:sky/widgets/basic.dart'; 8 import 'package:sky/widgets/basic.dart';
14 import 'package:sky/widgets/card.dart'; 9 import 'package:sky/widgets/card.dart';
10 import 'package:sky/widgets/dismissable.dart';
15 import 'package:sky/widgets/scaffold.dart'; 11 import 'package:sky/widgets/scaffold.dart';
16 import 'package:sky/widgets/variable_height_scrollable.dart'; 12 import 'package:sky/widgets/variable_height_scrollable.dart';
17 import 'package:sky/widgets/theme.dart'; 13 import 'package:sky/widgets/theme.dart';
18 import 'package:sky/widgets/tool_bar.dart'; 14 import 'package:sky/widgets/tool_bar.dart';
19 import 'package:sky/widgets/widget.dart'; 15 import 'package:sky/widgets/widget.dart';
20 16
21 17
22 const int _kCardDismissFadeoutMS = 300;
23 const double _kMinFlingVelocity = 700.0;
24 const double _kMinFlingVelocityDelta = 400.0;
25 const double _kDismissCardThreshold = 0.6;
26
27 class CardCollectionApp extends App { 18 class CardCollectionApp extends App {
28 19
29 final TextStyle cardLabelStyle = 20 final TextStyle cardLabelStyle =
30 new TextStyle(color: White, fontSize: 18.0, fontWeight: bold); 21 new TextStyle(color: White, fontSize: 18.0, fontWeight: bold);
31 22
32 final List<double> cardHeights = [ 23 final List<double> cardHeights = [
33 48.0, 64.0, 82.0, 46.0, 60.0, 55.0, 84.0, 96.0, 50.0, 24 48.0, 64.0, 82.0, 46.0, 60.0, 55.0, 84.0, 96.0, 50.0,
34 48.0, 64.0, 82.0, 46.0, 60.0, 55.0, 84.0, 96.0, 50.0, 25 48.0, 64.0, 82.0, 46.0, 60.0, 55.0, 84.0, 96.0, 50.0,
35 48.0, 64.0, 82.0, 46.0, 60.0, 55.0, 84.0, 96.0, 50.0, 26 48.0, 64.0, 82.0, 46.0, 60.0, 55.0, 84.0, 96.0, 50.0,
36 48.0, 64.0, 82.0, 46.0, 60.0, 55.0, 84.0, 96.0, 50.0 27 48.0, 64.0, 82.0, 46.0, 60.0, 55.0, 84.0, 96.0, 50.0
37 ]; 28 ];
38 29
39 List<int> visibleCardIndices; 30 List<int> visibleCardIndices;
40 31
41 CardCollectionApp() { 32 void initState() {
42 _activeCardTransform = new AnimationBuilder()
43 ..position = new AnimatedType<Point>(Point.origin)
44 ..opacity = new AnimatedType<double>(1.0, end: 0.0);
45
46 _activeCardAnimation = _activeCardTransform.createPerformance(
47 [_activeCardTransform.position, _activeCardTransform.opacity],
48 duration: new Duration(milliseconds: _kCardDismissFadeoutMS));
49 _activeCardAnimation.addListener(_handleAnimationProgressChanged);
50
51 visibleCardIndices = new List.generate(cardHeights.length, (i) => i); 33 visibleCardIndices = new List.generate(cardHeights.length, (i) => i);
34 super.initState();
52 } 35 }
53 36
54 int _activeCardIndex = -1; 37 void dismissCard(int cardIndex) {
55 AnimationBuilder _activeCardTransform;
56 AnimationPerformance _activeCardAnimation;
57 double _activeCardWidth;
58 double _activeCardDragX = 0.0;
59 bool _activeCardDragUnderway = false;
60
61 Point get _activeCardDragEndPoint {
62 return new Point(_activeCardDragX.sign * _activeCardWidth * _kDismissCardThr eshold, 0.0);
63 }
64
65 void _handleAnimationProgressChanged() {
66 setState(() { 38 setState(() {
67 if (_activeCardAnimation.isCompleted && !_activeCardDragUnderway) 39 visibleCardIndices.remove(cardIndex);
68 visibleCardIndices.remove(_activeCardIndex);
69 }); 40 });
70 } 41 }
71 42
72 void _handleSizeChanged(Size newSize) {
73 _activeCardWidth = newSize.width;
74 _activeCardTransform.position.end = _activeCardDragEndPoint;
75 }
76
77 void _handlePointerDown(sky.PointerEvent event, int cardIndex) {
78 setState(() {
79 _activeCardIndex = cardIndex;
80 _activeCardDragUnderway = true;
81 _activeCardDragX = 0.0;
82 _activeCardAnimation.progress = 0.0;
83 });
84 }
85
86 void _handlePointerMove(sky.PointerEvent event) {
87 if (_activeCardWidth == null || _activeCardIndex < 0)
88 return;
89
90 double oldDragX = _activeCardDragX;
91 _activeCardDragX += event.dx;
92 setState(() {
93 if (!_activeCardAnimation.isAnimating) {
94 if (oldDragX.sign != _activeCardDragX.sign)
95 _activeCardTransform.position.end = _activeCardDragEndPoint;
96 _activeCardAnimation.progress = _activeCardDragX.abs() / (_activeCardWid th * _kDismissCardThreshold);
97 }
98 });
99 }
100
101 void _handlePointerUpOrCancel(_) {
102 if (_activeCardWidth == null || _activeCardIndex < 0)
103 return;
104
105 setState(() {
106 _activeCardDragUnderway = false;
107 if (_activeCardAnimation.isCompleted)
108 visibleCardIndices.remove(_activeCardIndex);
109 else if (!_activeCardAnimation.isAnimating)
110 _activeCardAnimation.progress = 0.0;
111 });
112 }
113
114 bool _isHorizontalFlingGesture(sky.GestureEvent event) {
115 double vx = event.velocityX.abs();
116 double vy = event.velocityY.abs();
117 return vx - vy > _kMinFlingVelocityDelta && vx > _kMinFlingVelocity;
118 }
119
120 void _handleFlingStart(sky.GestureEvent event) {
121 if (_activeCardWidth == null || _activeCardIndex < 0)
122 return;
123
124 _activeCardDragUnderway = false;
125
126 if (_isHorizontalFlingGesture(event)) {
127 double distance = 1.0 - _activeCardAnimation.progress;
128 if (distance > 0.0) {
129 double duration = 250.0 * 1000.0 * distance / event.velocityX.abs();
130 _activeCardDragX = event.velocityX.sign;
131 _activeCardAnimation.timeline.animateTo(1.0, duration: duration);
132 }
133 }
134 }
135
136 Widget _buildCard(int cardIndex) {
137 Widget label = new Center(child: new Text("Item ${cardIndex}", style: cardLa belStyle));
138 Color color = lerpColor(Red[500], Blue[500], cardIndex / cardHeights.length) ;
139 Widget card = new Card(
140 child: new Padding(child: label, padding: const EdgeDims.all(8.0)),
141 color: color
142 );
143
144 // TODO(hansmuller) The code below changes the card's widget tree when
145 // the user starts dragging it. Currently this causes Sky to drop the
146 // rest of the pointer gesture, see https://github.com/domokit/mojo/issues/3 12.
147 // As a workaround, always create the Transform and Opacity nodes.
148 if (cardIndex == _activeCardIndex) {
149 card = _activeCardTransform.build(card);
150 } else {
151 card = new Transform(child: card, transform: new Matrix4.identity());
152 card = new Opacity(child: card, opacity: 1.0);
153 }
154
155 return new Listener(
156 key: "$cardIndex",
157 child: new Container(child: card, height: cardHeights[cardIndex]),
158 onPointerDown: (event) { _handlePointerDown(event, cardIndex); },
159 onPointerMove: _handlePointerMove,
160 onPointerUp: _handlePointerUpOrCancel,
161 onPointerCancel: _handlePointerUpOrCancel,
162 onGestureFlingStart: _handleFlingStart
163 );
164 }
165
166 Widget _builder(int index) { 43 Widget _builder(int index) {
167 if (index >= visibleCardIndices.length) 44 if (index >= visibleCardIndices.length)
168 return null; 45 return null;
169 return _buildCard(visibleCardIndices[index]); 46
47 int cardIndex = visibleCardIndices[index];
48 Color color = lerpColor(Red[500], Blue[500], cardIndex / cardHeights.length) ;
49 Widget label = new Text("Item ${cardIndex}", style: cardLabelStyle);
50 return new Dismissable(
51 key: cardIndex.toString(),
52 onDismissed: () { dismissCard(cardIndex); },
53 child: new Card(
54 color: color,
55 child: new Container(
56 height: cardHeights[cardIndex],
57 padding: const EdgeDims.all(8.0),
58 child: new Center(child: label)
59 )
60 )
61 );
170 } 62 }
171 63
172 Widget build() { 64 Widget build() {
173 Widget cardCollection = new Container( 65 Widget cardCollection = new Container(
174 padding: const EdgeDims.symmetric(vertical: 12.0, horizontal: 8.0), 66 padding: const EdgeDims.symmetric(vertical: 12.0, horizontal: 8.0),
175 decoration: new BoxDecoration(backgroundColor: Theme.of(this).primarySwatc h[50]), 67 decoration: new BoxDecoration(backgroundColor: Theme.of(this).primarySwatc h[50]),
176 child: new VariableHeightScrollable( 68 child: new VariableHeightScrollable(
177 builder: _builder, 69 builder: _builder,
178 token: visibleCardIndices.length 70 token: visibleCardIndices.length
179 ) 71 )
180 ); 72 );
181 73
182 return new Scaffold( 74 return new Scaffold(
183 toolbar: new ToolBar(center: new Text('Swipe Away')), 75 toolbar: new ToolBar(center: new Text('Swipe Away')),
184 body: new SizeObserver(child: cardCollection, callback: _handleSizeChanged ) 76 body: cardCollection
185 ); 77 );
186 } 78 }
187 } 79 }
188 80
189 void main() { 81 void main() {
190 runApp(new CardCollectionApp()); 82 runApp(new CardCollectionApp());
191 } 83 }
OLDNEW
« no previous file with comments | « sky/sdk/BUILD.gn ('k') | sky/sdk/lib/widgets/dismissable.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698