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

Side by Side Diff: sky/sdk/lib/widgets/block_viewport.dart

Issue 1227823012: Move VariableHeightScrollable to sdk/lib/widgets (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: 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
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:collection';
6
5 import '../rendering/block.dart'; 7 import '../rendering/block.dart';
6 import '../rendering/box.dart'; 8 import '../rendering/box.dart';
7 import '../rendering/object.dart'; 9 import '../rendering/object.dart';
8 import 'widget.dart'; 10 import 'widget.dart';
9 11
10 // return null if index is greater than index of last entry 12 // return null if index is greater than index of last entry
11 typedef Widget IndexedBuilder(int index); 13 typedef Widget IndexedBuilder(int index);
12 14
15 typedef void LayoutChangedCallback(
16 int firstVisibleChildIndex,
17 int visibleChildCount,
18 UnmodifiableListView<double> childOffsets,
19 bool didReachLastChild
20 );
21
13 class _Key { 22 class _Key {
14 const _Key(this.type, this.key); 23 const _Key(this.type, this.key);
15 factory _Key.fromWidget(Widget widget) => new _Key(widget.runtimeType, widget. key); 24 factory _Key.fromWidget(Widget widget) => new _Key(widget.runtimeType, widget. key);
16 final Type type; 25 final Type type;
17 final String key; 26 final String key;
18 bool operator ==(other) => other is _Key && other.type == type && other.key == key; 27 bool operator ==(other) => other is _Key && other.type == type && other.key == key;
19 int get hashCode => 373 * 37 * type.hashCode + key.hashCode; 28 int get hashCode => 373 * 37 * type.hashCode + key.hashCode;
20 } 29 }
21 30
22 class BlockViewport extends RenderObjectWrapper { 31 class BlockViewport extends RenderObjectWrapper {
23 BlockViewport({ this.builder, this.startOffset, this.token, String key }) 32 BlockViewport({ this.builder, this.startOffset, this.token, this.onLayoutChang ed, String key })
24 : super(key: key); 33 : super(key: key);
25 34
26 IndexedBuilder builder; 35 IndexedBuilder builder;
27 double startOffset; 36 double startOffset;
28 Object token; 37 Object token;
38 LayoutChangedCallback onLayoutChanged;
29 39
30 RenderBlockViewport get root => super.root; 40 RenderBlockViewport get root => super.root;
31 RenderBlockViewport createNode() => new RenderBlockViewport(); 41 RenderBlockViewport createNode() => new RenderBlockViewport();
32 42
33 Map<_Key, Widget> _childrenByKey = new Map<_Key, Widget>(); 43 Map<_Key, Widget> _childrenByKey = new Map<_Key, Widget>();
34 44
35 void walkChildren(WidgetTreeWalker walker) { 45 void walkChildren(WidgetTreeWalker walker) {
36 for (Widget child in _childrenByKey.values) 46 for (Widget child in _childrenByKey.values)
37 walker(child); 47 walker(child);
38 } 48 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 super.didUnmount(); 86 super.didUnmount();
77 } 87 }
78 88
79 // _offsets contains the offsets of each child from the top of the 89 // _offsets contains the offsets of each child from the top of the
80 // list up to the last one we've ever created, and the offset of the 90 // list up to the last one we've ever created, and the offset of the
81 // end of the last one. If there's no children, then the only offset 91 // end of the last one. If there's no children, then the only offset
82 // is 0.0. 92 // is 0.0.
83 List<double> _offsets = <double>[0.0]; 93 List<double> _offsets = <double>[0.0];
84 int _currentStartIndex = 0; 94 int _currentStartIndex = 0;
85 int _currentChildCount = 0; 95 int _currentChildCount = 0;
96 bool _didReachLastChild = false;
86 97
87 int _findIndexForOffsetBeforeOrAt(double offset) { 98 int _findIndexForOffsetBeforeOrAt(double offset) {
88 int left = 0; 99 int left = 0;
89 int right = _offsets.length - 1; 100 int right = _offsets.length - 1;
90 while (right >= left) { 101 while (right >= left) {
91 int middle = left + ((right - left) ~/ 2); 102 int middle = left + ((right - left) ~/ 2);
92 if (_offsets[middle] < offset) { 103 if (_offsets[middle] < offset) {
93 left = middle + 1; 104 left = middle + 1;
94 } else if (_offsets[middle] > offset) { 105 } else if (_offsets[middle] > offset) {
95 right = middle - 1; 106 right = middle - 1;
(...skipping 10 matching lines...) Expand all
106 retainStatefulRenderObjectWrapper(newNode); 117 retainStatefulRenderObjectWrapper(newNode);
107 if (startOffset != newNode.startOffset) { 118 if (startOffset != newNode.startOffset) {
108 _dirty = true; 119 _dirty = true;
109 startOffset = newNode.startOffset; 120 startOffset = newNode.startOffset;
110 } 121 }
111 if (token != newNode.token || builder != newNode.builder) { 122 if (token != newNode.token || builder != newNode.builder) {
112 _dirty = true; 123 _dirty = true;
113 builder = newNode.builder; 124 builder = newNode.builder;
114 token = newNode.token; 125 token = newNode.token;
115 _offsets = <double>[0.0]; 126 _offsets = <double>[0.0];
127 _didReachLastChild = false;
116 } 128 }
117 return true; 129 return true;
118 } 130 }
119 131
120 void syncRenderObject(BlockViewport old) { 132 void syncRenderObject(BlockViewport old) {
121 super.syncRenderObject(old); 133 super.syncRenderObject(old);
122 if (_dirty) { 134 if (_dirty) {
123 root.markNeedsLayout(); 135 root.markNeedsLayout();
124 } else { 136 } else {
125 if (_currentChildCount > 0) { 137 if (_currentChildCount > 0) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 if (_offsets.length > 1) { 201 if (_offsets.length > 1) {
190 haveChildren = true; 202 haveChildren = true;
191 } else { 203 } else {
192 Widget widget = _getWidget(startIndex, innerConstraints); 204 Widget widget = _getWidget(startIndex, innerConstraints);
193 if (widget != null) { 205 if (widget != null) {
194 newChildren[new _Key.fromWidget(widget)] = widget; 206 newChildren[new _Key.fromWidget(widget)] = widget;
195 builtChildren[startIndex] = widget; 207 builtChildren[startIndex] = widget;
196 haveChildren = true; 208 haveChildren = true;
197 } else { 209 } else {
198 haveChildren = false; 210 haveChildren = false;
211 _didReachLastChild = true;
199 } 212 }
200 } 213 }
201 } else { 214 } else {
202 startIndex = _findIndexForOffsetBeforeOrAt(startOffset); 215 startIndex = _findIndexForOffsetBeforeOrAt(startOffset);
203 if (startIndex == _offsets.length - 1) { 216 if (startIndex == _offsets.length - 1) {
204 // We don't have an offset on the list that is beyond the start offset. 217 // We don't have an offset on the list that is beyond the start offset.
205 assert(_offsets.last <= startOffset); 218 assert(_offsets.last <= startOffset);
206 // Fill the list until this isn't true or until we know that the 219 // Fill the list until this isn't true or until we know that the
207 // list is complete (and thus we are overscrolled). 220 // list is complete (and thus we are overscrolled).
208 while (true) { 221 while (true) {
209 Widget widget = _getWidget(startIndex, innerConstraints); 222 Widget widget = _getWidget(startIndex, innerConstraints);
210 if (widget == null) 223 if (widget == null) {
224 _didReachLastChild = true;
211 break; 225 break;
226 }
212 _Key widgetKey = new _Key.fromWidget(widget); 227 _Key widgetKey = new _Key.fromWidget(widget);
213 if (_offsets.last > startOffset) { 228 if (_offsets.last > startOffset) {
214 newChildren[widgetKey] = widget; 229 newChildren[widgetKey] = widget;
215 builtChildren[startIndex] = widget; 230 builtChildren[startIndex] = widget;
216 break; 231 break;
217 } 232 }
218 if (!_childrenByKey.containsKey(widgetKey)) { 233 if (!_childrenByKey.containsKey(widgetKey)) {
219 // we don't actually need this one, release it 234 // we don't actually need this one, release it
220 syncChild(null, widget, null); 235 syncChild(null, widget, null);
221 } // else we'll get rid of it later, when we remove old children 236 } // else we'll get rid of it later, when we remove old children
222 startIndex += 1; 237 startIndex += 1;
223 assert(startIndex == _offsets.length - 1); 238 assert(startIndex == _offsets.length - 1);
224 } 239 }
225 if (_offsets.last > startOffset) { 240 if (_offsets.last > startOffset) {
226 // If we're here, we have at least one child, so our list has 241 // If we're here, we have at least one child, so our list has
227 // at least two offsets, the top of the child and the bottom 242 // at least two offsets, the top of the child and the bottom
228 // of the child. 243 // of the child.
229 assert(_offsets.length >= 2); 244 assert(_offsets.length >= 2);
230 assert(startIndex == _offsets.length - 2); 245 assert(startIndex == _offsets.length - 2);
231 haveChildren = true; 246 haveChildren = true;
232 } else { 247 } else {
233 // If we're here, there are no children to show. 248 // If we're here, there are no children to show.
234 haveChildren = false; 249 haveChildren = false;
235 } 250 }
236 } else { 251 } else {
237 haveChildren = true; 252 haveChildren = true;
238 } 253 }
239 } 254 }
240 assert(haveChildren != null); 255 assert(haveChildren != null);
256 assert(haveChildren || _didReachLastChild);
241 257
242 assert(startIndex >= 0); 258 assert(startIndex >= 0);
243 assert(startIndex < _offsets.length); 259 assert(startIndex < _offsets.length);
244 260
245 int index = startIndex; 261 int index = startIndex;
246 if (haveChildren) { 262 if (haveChildren) {
247 // Build all the widgets we need. 263 // Build all the widgets we need.
248 root.startOffset = _offsets[index] - startOffset; 264 root.startOffset = _offsets[index] - startOffset;
249 while (_offsets[index] < endOffset) { 265 while (_offsets[index] < endOffset) {
250 if (!builtChildren.containsKey(index)) { 266 if (!builtChildren.containsKey(index)) {
251 Widget widget = _getWidget(index, innerConstraints); 267 Widget widget = _getWidget(index, innerConstraints);
252 if (widget == null) 268 if (widget == null) {
253 break; // reached the end of the list 269 _didReachLastChild = true;
270 break;
271 }
254 newChildren[new _Key.fromWidget(widget)] = widget; 272 newChildren[new _Key.fromWidget(widget)] = widget;
255 builtChildren[index] = widget; 273 builtChildren[index] = widget;
256 } 274 }
257 assert(builtChildren[index] != null); 275 assert(builtChildren[index] != null);
258 index += 1; 276 index += 1;
259 } 277 }
260 } 278 }
261 279
262 // Remove any old children. 280 // Remove any old children.
263 for (_Key oldChildKey in _childrenByKey.keys) { 281 for (_Key oldChildKey in _childrenByKey.keys) {
(...skipping 16 matching lines...) Expand all
280 root.add(widget.root, before: nextSibling); 298 root.add(widget.root, before: nextSibling);
281 } 299 }
282 widget.updateSlot(nextSibling); 300 widget.updateSlot(nextSibling);
283 nextSibling = widget.root; 301 nextSibling = widget.root;
284 } 302 }
285 } 303 }
286 304
287 _childrenByKey = newChildren; 305 _childrenByKey = newChildren;
288 _currentStartIndex = startIndex; 306 _currentStartIndex = startIndex;
289 _currentChildCount = _childrenByKey.length; 307 _currentChildCount = _childrenByKey.length;
308
309 if (onLayoutChanged != null) {
310 onLayoutChanged(
311 _currentStartIndex,
312 _currentChildCount,
313 new UnmodifiableListView<double>(_offsets),
314 _didReachLastChild
315 );
316 }
290 } 317 }
291 318
292 } 319 }
OLDNEW
« no previous file with comments | « sky/sdk/example/widgets/card_collection.dart ('k') | sky/sdk/lib/widgets/variable_height_scrollable.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698