diff --git a/sky/packages/sky/example/address_book/lib/main.dart b/sky/packages/sky/example/address_book/lib/main.dart index d5eb926d7394fa397fcb07258ffa971c25dc2db2..6a87bc6dd9868d8525e353adcf835c4047afa657 100644 --- a/sky/packages/sky/example/address_book/lib/main.dart +++ b/sky/packages/sky/example/address_book/lib/main.dart @@ -17,7 +17,7 @@ import 'package:sky/widgets/icon_button.dart'; import 'package:sky/widgets/material.dart'; import 'package:sky/widgets/navigator.dart'; import 'package:sky/widgets/scaffold.dart'; -import 'package:sky/widgets/scrollable_viewport.dart'; +import 'package:sky/widgets/scrollable.dart'; import 'package:sky/widgets/task_description.dart'; import 'package:sky/widgets/theme.dart'; import 'package:sky/widgets/tool_bar.dart'; diff --git a/sky/packages/sky/example/demo_launcher/lib/main.dart b/sky/packages/sky/example/demo_launcher/lib/main.dart index 15ae01645032b300ded577a0fcd962f47668dae7..2c64251b93481f1021b691bdbfa57af074738720 100644 --- a/sky/packages/sky/example/demo_launcher/lib/main.dart +++ b/sky/packages/sky/example/demo_launcher/lib/main.dart @@ -16,7 +16,7 @@ import 'package:sky/widgets/scaffold.dart'; import 'package:sky/widgets/task_description.dart'; import 'package:sky/widgets/theme.dart'; import 'package:sky/widgets/tool_bar.dart'; -import 'package:sky/widgets/scrollable_list.dart'; +import 'package:sky/widgets/scrollable.dart'; import 'package:sky/widgets/ink_well.dart'; AssetBundle _initBundle() { diff --git a/sky/packages/sky/example/fitness/lib/main.dart b/sky/packages/sky/example/fitness/lib/main.dart index 95907beaf0f0547353559d3540d2e90be0fcd3db..405f57c1624d7a390b389535909af94adbeba603 100644 --- a/sky/packages/sky/example/fitness/lib/main.dart +++ b/sky/packages/sky/example/fitness/lib/main.dart @@ -25,8 +25,7 @@ import 'package:sky/widgets/ink_well.dart'; import 'package:sky/widgets/material.dart'; import 'package:sky/widgets/radio.dart'; import 'package:sky/widgets/scaffold.dart'; -import 'package:sky/widgets/scrollable_list.dart'; -import 'package:sky/widgets/scrollable_viewport.dart'; +import 'package:sky/widgets/scrollable.dart'; import 'package:sky/widgets/snack_bar.dart'; import 'package:sky/widgets/tool_bar.dart'; import 'package:sky/widgets/card.dart'; diff --git a/sky/packages/sky/example/stocks/lib/main.dart b/sky/packages/sky/example/stocks/lib/main.dart index e119b61e9aba012e538ed0ff92d49534146634a4..a197cfebb0366e6ff3d748d63c56ed68fcecd70d 100644 --- a/sky/packages/sky/example/stocks/lib/main.dart +++ b/sky/packages/sky/example/stocks/lib/main.dart @@ -7,40 +7,39 @@ library stocks; import 'dart:math' as math; import 'dart:sky' as sky; +import 'package:sky/editing/input.dart'; +import 'package:sky/painting/text_style.dart'; +import 'package:sky/rendering/box.dart'; import 'package:sky/theme/colors.dart' as colors; import 'package:sky/theme/typography.dart' as typography; import 'package:sky/widgets/basic.dart'; +import 'package:sky/widgets/checkbox.dart'; import 'package:sky/widgets/default_text_style.dart'; -import 'package:sky/widgets/navigator.dart'; -import 'package:sky/widgets/theme.dart'; -import 'package:sky/widgets/widget.dart'; -import 'package:sky/widgets/task_description.dart'; -import 'package:sky/rendering/box.dart'; -import 'package:sky/editing/input.dart'; -import 'package:sky/widgets/drawer.dart'; +import 'package:sky/widgets/dialog.dart'; import 'package:sky/widgets/drawer_divider.dart'; import 'package:sky/widgets/drawer_header.dart'; import 'package:sky/widgets/drawer_item.dart'; +import 'package:sky/widgets/drawer.dart'; +import 'package:sky/widgets/flat_button.dart'; import 'package:sky/widgets/floating_action_button.dart'; -import 'package:sky/widgets/icon.dart'; import 'package:sky/widgets/icon_button.dart'; +import 'package:sky/widgets/icon.dart'; +import 'package:sky/widgets/ink_well.dart'; +import 'package:sky/widgets/material.dart'; import 'package:sky/widgets/modal_overlay.dart'; +import 'package:sky/widgets/navigator.dart'; +import 'package:sky/widgets/popup_menu_item.dart'; import 'package:sky/widgets/popup_menu.dart'; import 'package:sky/widgets/radio.dart'; -import 'package:sky/widgets/snack_bar.dart'; import 'package:sky/widgets/scaffold.dart'; +import 'package:sky/widgets/scrollable.dart'; +import 'package:sky/widgets/snack_bar.dart'; +import 'package:sky/widgets/switch.dart'; import 'package:sky/widgets/tabs.dart'; +import 'package:sky/widgets/task_description.dart'; +import 'package:sky/widgets/theme.dart'; import 'package:sky/widgets/tool_bar.dart'; -import 'package:sky/widgets/scrollable_list.dart'; -import 'package:sky/widgets/material.dart'; -import 'package:sky/widgets/checkbox.dart'; -import 'package:sky/widgets/popup_menu_item.dart'; -import 'package:sky/painting/text_style.dart'; -import 'package:sky/widgets/ink_well.dart'; -import 'package:sky/widgets/dialog.dart'; -import 'package:sky/widgets/flat_button.dart'; -import 'package:sky/widgets/scrollable_viewport.dart'; -import 'package:sky/widgets/switch.dart'; +import 'package:sky/widgets/widget.dart'; //TODO(jimsimon): Is this needed? export 'package:sky/widgets/popup_menu.dart' show PopupMenuStatus; diff --git a/sky/packages/sky/example/widgets/card_collection.dart b/sky/packages/sky/example/widgets/card_collection.dart index 37fc2b521bd41abb4d48c7a92827e5b63a9da5ea..b0565b7da515e00ae6b556da33fb19273d1a09fa 100644 --- a/sky/packages/sky/example/widgets/card_collection.dart +++ b/sky/packages/sky/example/widgets/card_collection.dart @@ -10,7 +10,7 @@ import 'package:sky/widgets/block_viewport.dart'; import 'package:sky/widgets/card.dart'; import 'package:sky/widgets/dismissable.dart'; import 'package:sky/widgets/icon.dart'; -import 'package:sky/widgets/variable_height_scrollable.dart'; +import 'package:sky/widgets/scrollable.dart'; import 'package:sky/widgets/scaffold.dart'; import 'package:sky/widgets/theme.dart'; import 'package:sky/widgets/tool_bar.dart'; diff --git a/sky/packages/sky/lib/widgets/dialog.dart b/sky/packages/sky/lib/widgets/dialog.dart index 781137d6e1d9e50a5e302b76d26eeeb110ac08de..b73aa109c8ef2e96b251ba4cd96bafe8c9785107 100644 --- a/sky/packages/sky/lib/widgets/dialog.dart +++ b/sky/packages/sky/lib/widgets/dialog.dart @@ -10,7 +10,7 @@ import 'package:sky/widgets/default_text_style.dart'; import 'package:sky/widgets/focus.dart'; import 'package:sky/widgets/material.dart'; import 'package:sky/widgets/navigator.dart'; -import 'package:sky/widgets/scrollable_viewport.dart'; +import 'package:sky/widgets/scrollable.dart'; import 'package:sky/widgets/theme.dart'; typedef Widget DialogBuilder(Navigator navigator); diff --git a/sky/packages/sky/lib/widgets/drawer.dart b/sky/packages/sky/lib/widgets/drawer.dart index d0e17e1f76c4770542a11eab0839deb8801a4dde..398926216e620f6d83305dfe061ab7963d89d34a 100644 --- a/sky/packages/sky/lib/widgets/drawer.dart +++ b/sky/packages/sky/lib/widgets/drawer.dart @@ -13,7 +13,7 @@ import 'package:sky/widgets/animated_container.dart'; import 'package:sky/widgets/animation_intentions.dart'; import 'package:sky/widgets/basic.dart'; import 'package:sky/widgets/navigator.dart'; -import 'package:sky/widgets/scrollable_viewport.dart'; +import 'package:sky/widgets/scrollable.dart'; import 'package:sky/widgets/theme.dart'; export 'package:sky/animation/animation_performance.dart' show AnimationStatus; diff --git a/sky/packages/sky/lib/widgets/fixed_height_scrollable.dart b/sky/packages/sky/lib/widgets/fixed_height_scrollable.dart deleted file mode 100644 index 8ed31ad7253d99f8f081cd72dc00cf75031b9742..0000000000000000000000000000000000000000 --- a/sky/packages/sky/lib/widgets/fixed_height_scrollable.dart +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:math' as math; - -import 'package:sky/animation/scroll_behavior.dart'; -import 'package:sky/widgets/basic.dart'; -import 'package:sky/widgets/scrollable.dart'; - -abstract class FixedHeightScrollable extends Scrollable { - - FixedHeightScrollable({ Key key, this.itemHeight, this.padding }) - : super(key: key) { - assert(itemHeight != null); - } - - EdgeDims padding; - double itemHeight; - - /// Subclasses must implement `get itemCount` to tell FixedHeightScrollable - /// how many items there are in the list. - int get itemCount; - int _previousItemCount; - - void syncFields(FixedHeightScrollable source) { - padding = source.padding; - itemHeight = source.itemHeight; - super.syncFields(source); - } - - ScrollBehavior createScrollBehavior() => new OverscrollBehavior(); - OverscrollBehavior get scrollBehavior => super.scrollBehavior; - - double _height; - void _handleSizeChanged(Size newSize) { - setState(() { - _height = newSize.height; - scrollBehavior.containerSize = _height; - }); - } - - void _updateContentsHeight() { - double contentsHeight = itemHeight * itemCount; - if (padding != null) - contentsHeight += padding.top + padding.bottom; - scrollBehavior.contentsSize = contentsHeight; - } - - void _updateScrollOffset() { - if (scrollOffset > scrollBehavior.maxScrollOffset) - settleScrollOffset(); - } - - Widget buildContent() { - if (itemCount != _previousItemCount) { - _previousItemCount = itemCount; - _updateContentsHeight(); - _updateScrollOffset(); - } - - int itemShowIndex = 0; - int itemShowCount = 0; - double offsetY = 0.0; - if (_height != null && _height > 0.0) { - if (scrollOffset < 0.0) { - double visibleHeight = _height + scrollOffset; - itemShowCount = (visibleHeight / itemHeight).round() + 1; - offsetY = scrollOffset; - } else { - itemShowCount = (_height / itemHeight).ceil(); - double alignmentDelta = -scrollOffset % itemHeight; - double drawStart; - if (alignmentDelta != 0.0) { - alignmentDelta -= itemHeight; - itemShowCount += 1; - drawStart = scrollOffset + alignmentDelta; - offsetY = -alignmentDelta; - } else { - drawStart = scrollOffset; - } - itemShowIndex = math.max(0, (drawStart / itemHeight).floor()); - } - } - - List items = buildItems(itemShowIndex, itemShowCount); - assert(items.every((item) => item.key != null)); - - // TODO(ianh): Refactor this so that it does the building in the - // same frame as the size observing, similar to BlockViewport, but - // keeping the fixed-height optimisations. - return new SizeObserver( - callback: _handleSizeChanged, - child: new Viewport( - offset: offsetY, - child: new Container( - padding: padding, - child: new Block(items) - ) - ) - ); - } - - List buildItems(int start, int count); - -} diff --git a/sky/packages/sky/lib/widgets/popup_menu.dart b/sky/packages/sky/lib/widgets/popup_menu.dart index 6ebbd260117f5b5f6e9b183f586b197baed71318..9a3eaf2ecbcbeac888081ecdc1b548838cbe35cb 100644 --- a/sky/packages/sky/lib/widgets/popup_menu.dart +++ b/sky/packages/sky/lib/widgets/popup_menu.dart @@ -14,7 +14,7 @@ import 'package:sky/widgets/animated_component.dart'; import 'package:sky/widgets/basic.dart'; import 'package:sky/widgets/navigator.dart'; import 'package:sky/widgets/popup_menu_item.dart'; -import 'package:sky/widgets/scrollable_viewport.dart'; +import 'package:sky/widgets/scrollable.dart'; export 'package:sky/animation/animation_performance.dart' show AnimationStatus; diff --git a/sky/packages/sky/lib/widgets/scrollable.dart b/sky/packages/sky/lib/widgets/scrollable.dart index 179fba104dd4d82cd2bdbb9309d5175c03bbe8e0..85a45c1259cf42e75de52d3e3e8d31d4af05507d 100644 --- a/sky/packages/sky/lib/widgets/scrollable.dart +++ b/sky/packages/sky/lib/widgets/scrollable.dart @@ -2,16 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:math' as math; import 'dart:sky' as sky; import 'package:newton/newton.dart'; -import 'package:sky/animation/animation_performance.dart'; import 'package:sky/animation/animated_simulation.dart'; import 'package:sky/animation/animated_value.dart'; +import 'package:sky/animation/animation_performance.dart'; import 'package:sky/animation/curves.dart'; import 'package:sky/animation/scroll_behavior.dart'; import 'package:sky/theme/view_configuration.dart' as config; import 'package:sky/widgets/basic.dart'; +import 'package:sky/widgets/block_viewport.dart'; +import 'package:sky/widgets/scrollable.dart'; +import 'package:sky/widgets/widget.dart'; + +export 'package:sky/widgets/block_viewport.dart' show BlockViewportLayoutState; const double _kMillisecondsPerSecond = 1000.0; @@ -27,6 +33,8 @@ abstract class ScrollClient { enum ScrollDirection { vertical, horizontal } +/// A base class for scrollable widgets that reacts to user input and generates +/// a scrollOffset. abstract class Scrollable extends StatefulComponent { Scrollable({ @@ -203,3 +211,282 @@ abstract class Scrollable extends StatefulComponent { scrollBy(-event.offsetY); } } + +/// A simple scrollable widget that has a single child. Use this component if +/// you are not worried about offscreen widgets consuming resources. +class ScrollableViewport extends Scrollable { + ScrollableViewport({ Key key, this.child }) : super(key: key); + + Widget child; + + void syncFields(ScrollableViewport source) { + child = source.child; + super.syncFields(source); + } + + ScrollBehavior createScrollBehavior() => new FlingBehavior(); + FlingBehavior get scrollBehavior => super.scrollBehavior; + + double _viewportHeight = 0.0; + double _childHeight = 0.0; + void _handleViewportSizeChanged(Size newSize) { + _viewportHeight = newSize.height; + _updateScrollBehaviour(); + } + void _handleChildSizeChanged(Size newSize) { + _childHeight = newSize.height; + _updateScrollBehaviour(); + } + void _updateScrollBehaviour() { + scrollBehavior.contentsSize = _childHeight; + scrollBehavior.containerSize = _viewportHeight; + if (scrollOffset > scrollBehavior.maxScrollOffset) + settleScrollOffset(); + } + + Widget buildContent() { + return new SizeObserver( + callback: _handleViewportSizeChanged, + child: new Viewport( + offset: scrollOffset, + child: new SizeObserver( + callback: _handleChildSizeChanged, + child: child + ) + ) + ); + } +} + +/// A mashup of [ScrollableViewport] and [Block]. Useful when you have a small, +/// fixed number of children that you wish to arrange in a block layout and that +/// might exceed the height of its container (and therefore need to scroll). +class ScrollableBlock extends Component { + ScrollableBlock(this.children, { Key key }) : super(key: key); + + final List children; + + Widget build() { + return new ScrollableViewport( + child: new Block(children) + ); + } +} + +/// An optimized scrollable widget for a large number of children that are all +/// of the same height. Use this widget when you have a large number of children +/// or when you are concerned about offscreen widgets consuming resources. +abstract class FixedHeightScrollable extends Scrollable { + + FixedHeightScrollable({ Key key, this.itemHeight, this.padding }) + : super(key: key) { + assert(itemHeight != null); + } + + EdgeDims padding; + double itemHeight; + + /// Subclasses must implement `get itemCount` to tell FixedHeightScrollable + /// how many items there are in the list. + int get itemCount; + int _previousItemCount; + + void syncFields(FixedHeightScrollable source) { + padding = source.padding; + itemHeight = source.itemHeight; + super.syncFields(source); + } + + ScrollBehavior createScrollBehavior() => new OverscrollBehavior(); + OverscrollBehavior get scrollBehavior => super.scrollBehavior; + + double _height; + void _handleSizeChanged(Size newSize) { + setState(() { + _height = newSize.height; + scrollBehavior.containerSize = _height; + }); + } + + void _updateContentsHeight() { + double contentsHeight = itemHeight * itemCount; + if (padding != null) + contentsHeight += padding.top + padding.bottom; + scrollBehavior.contentsSize = contentsHeight; + } + + void _updateScrollOffset() { + if (scrollOffset > scrollBehavior.maxScrollOffset) + settleScrollOffset(); + } + + Widget buildContent() { + if (itemCount != _previousItemCount) { + _previousItemCount = itemCount; + _updateContentsHeight(); + _updateScrollOffset(); + } + + int itemShowIndex = 0; + int itemShowCount = 0; + double offsetY = 0.0; + if (_height != null && _height > 0.0) { + if (scrollOffset < 0.0) { + double visibleHeight = _height + scrollOffset; + itemShowCount = (visibleHeight / itemHeight).round() + 1; + offsetY = scrollOffset; + } else { + itemShowCount = (_height / itemHeight).ceil(); + double alignmentDelta = -scrollOffset % itemHeight; + double drawStart; + if (alignmentDelta != 0.0) { + alignmentDelta -= itemHeight; + itemShowCount += 1; + drawStart = scrollOffset + alignmentDelta; + offsetY = -alignmentDelta; + } else { + drawStart = scrollOffset; + } + itemShowIndex = math.max(0, (drawStart / itemHeight).floor()); + } + } + + List items = buildItems(itemShowIndex, itemShowCount); + assert(items.every((item) => item.key != null)); + + // TODO(ianh): Refactor this so that it does the building in the + // same frame as the size observing, similar to BlockViewport, but + // keeping the fixed-height optimisations. + return new SizeObserver( + callback: _handleSizeChanged, + child: new Viewport( + offset: offsetY, + child: new Container( + padding: padding, + child: new Block(items) + ) + ) + ); + } + + List buildItems(int start, int count); + +} + +typedef Widget ItemBuilder(T item); + +/// A wrapper around [FixedHeightScrollable] that helps you translate a list of +/// model objects into a scrollable list of widgets. Assumes all the widgets +/// have the same height. +class ScrollableList extends FixedHeightScrollable { + ScrollableList({ + Key key, + this.items, + this.itemBuilder, + double itemHeight, + EdgeDims padding + }) : super(key: key, itemHeight: itemHeight, padding: padding); + + List items; + ItemBuilder itemBuilder; + + void syncFields(ScrollableList source) { + items = source.items; + itemBuilder = source.itemBuilder; + super.syncFields(source); + } + + int get itemCount => items.length; + + List buildItems(int start, int count) { + List result = new List(); + int end = math.min(start + count, items.length); + for (int i = start; i < end; ++i) + result.add(itemBuilder(items[i])); + return result; + } +} + +/// A general scrollable list for a large number of children that might not all +/// have the same height. Prefer [FixedHeightScrollable] when all the children +/// have the same height because it can use that property to be more efficient. +/// Prefer [ScrollableViewport] with a single child. +class VariableHeightScrollable extends Scrollable { + VariableHeightScrollable({ + Key key, + this.builder, + this.token, + this.layoutState + }) : super(key: key); + + IndexedBuilder builder; + Object token; + BlockViewportLayoutState layoutState; + + // When the token changes the scrollable's contents may have + // changed. Remember as much so that after the new contents + // have been laid out we can adjust the scrollOffset so that + // the last page of content is still visible. + bool _contentsChanged = true; + + void initState() { + assert(layoutState != null); + super.initState(); + } + + void didMount() { + layoutState.addListener(_handleLayoutChanged); + super.didMount(); + } + + void didUnmount() { + layoutState.removeListener(_handleLayoutChanged); + super.didUnmount(); + } + + void syncFields(VariableHeightScrollable source) { + builder = source.builder; + if (token != source.token) + _contentsChanged = true; + token = source.token; + if (layoutState != source.layoutState) { + // Warning: this is unlikely to be what you intended. + assert(source.layoutState != null); + layoutState.removeListener(_handleLayoutChanged); + layoutState = source.layoutState; + layoutState.addListener(_handleLayoutChanged); + } + super.syncFields(source); + } + + ScrollBehavior createScrollBehavior() => new OverscrollBehavior(); + OverscrollBehavior get scrollBehavior => super.scrollBehavior; + + void _handleSizeChanged(Size newSize) { + scrollBehavior.containerSize = newSize.height; + } + + void _handleLayoutChanged() { + if (layoutState.didReachLastChild) { + scrollBehavior.contentsSize = layoutState.contentsSize; + if (_contentsChanged && scrollOffset > scrollBehavior.maxScrollOffset) { + _contentsChanged = false; + settleScrollOffset(); + } + } else { + scrollBehavior.contentsSize = double.INFINITY; + } + } + + Widget buildContent() { + return new SizeObserver( + callback: _handleSizeChanged, + child: new BlockViewport( + builder: builder, + layoutState: layoutState, + startOffset: scrollOffset, + token: token + ) + ); + } +} diff --git a/sky/packages/sky/lib/widgets/scrollable_list.dart b/sky/packages/sky/lib/widgets/scrollable_list.dart deleted file mode 100644 index b897ef2ff72d3cdf565355c3da150a1657ccc824..0000000000000000000000000000000000000000 --- a/sky/packages/sky/lib/widgets/scrollable_list.dart +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:math' as math; - -import 'package:sky/widgets/fixed_height_scrollable.dart'; -import 'package:sky/widgets/basic.dart'; - -typedef Widget ItemBuilder(T item); - -class ScrollableList extends FixedHeightScrollable { - ScrollableList({ - Key key, - this.items, - this.itemBuilder, - double itemHeight, - EdgeDims padding - }) : super(key: key, itemHeight: itemHeight, padding: padding); - - List items; - ItemBuilder itemBuilder; - - void syncFields(ScrollableList source) { - items = source.items; - itemBuilder = source.itemBuilder; - super.syncFields(source); - } - - int get itemCount => items.length; - - List buildItems(int start, int count) { - List result = new List(); - int end = math.min(start + count, items.length); - for (int i = start; i < end; ++i) - result.add(itemBuilder(items[i])); - return result; - } -} diff --git a/sky/packages/sky/lib/widgets/scrollable_viewport.dart b/sky/packages/sky/lib/widgets/scrollable_viewport.dart deleted file mode 100644 index 208fad3e1e28654521200be3eedeb5f8484e42eb..0000000000000000000000000000000000000000 --- a/sky/packages/sky/lib/widgets/scrollable_viewport.dart +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:sky/animation/scroll_behavior.dart'; -import 'package:sky/widgets/basic.dart'; -import 'package:sky/widgets/scrollable.dart'; - -class ScrollableViewport extends Scrollable { - - ScrollableViewport({ Key key, this.child }) : super(key: key); - - Widget child; - - void syncFields(ScrollableViewport source) { - child = source.child; - super.syncFields(source); - } - - ScrollBehavior createScrollBehavior() => new FlingBehavior(); - FlingBehavior get scrollBehavior => super.scrollBehavior; - - double _viewportHeight = 0.0; - double _childHeight = 0.0; - void _handleViewportSizeChanged(Size newSize) { - _viewportHeight = newSize.height; - _updateScrollBehaviour(); - } - void _handleChildSizeChanged(Size newSize) { - _childHeight = newSize.height; - _updateScrollBehaviour(); - } - void _updateScrollBehaviour() { - scrollBehavior.contentsSize = _childHeight; - scrollBehavior.containerSize = _viewportHeight; - if (scrollOffset > scrollBehavior.maxScrollOffset) - settleScrollOffset(); - } - - Widget buildContent() { - return new SizeObserver( - callback: _handleViewportSizeChanged, - child: new Viewport( - offset: scrollOffset, - child: new SizeObserver( - callback: _handleChildSizeChanged, - child: child - ) - ) - ); - } - -} - -class ScrollableBlock extends Component { - - ScrollableBlock(this.children, { Key key }) : super(key: key); - - final List children; - - Widget build() { - return new ScrollableViewport( - child: new Block(children) - ); - } - -} diff --git a/sky/packages/sky/lib/widgets/variable_height_scrollable.dart b/sky/packages/sky/lib/widgets/variable_height_scrollable.dart deleted file mode 100644 index e7fbfaecd8c8d6d0c2ed6e803b5fb55739fb8272..0000000000000000000000000000000000000000 --- a/sky/packages/sky/lib/widgets/variable_height_scrollable.dart +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:sky/animation/scroll_behavior.dart'; -import 'package:sky/widgets/basic.dart'; -import 'package:sky/widgets/block_viewport.dart'; -import 'package:sky/widgets/scrollable.dart'; -import 'package:sky/widgets/widget.dart'; - -export 'package:sky/widgets/block_viewport.dart' show BlockViewportLayoutState; - -class VariableHeightScrollable extends Scrollable { - VariableHeightScrollable({ - Key key, - this.builder, - this.token, - this.layoutState - }) : super(key: key); - - IndexedBuilder builder; - Object token; - BlockViewportLayoutState layoutState; - - // When the token changes the scrollable's contents may have - // changed. Remember as much so that after the new contents - // have been laid out we can adjust the scrollOffset so that - // the last page of content is still visible. - bool _contentsChanged = true; - - void initState() { - assert(layoutState != null); - super.initState(); - } - - void didMount() { - layoutState.addListener(_handleLayoutChanged); - super.didMount(); - } - - void didUnmount() { - layoutState.removeListener(_handleLayoutChanged); - super.didUnmount(); - } - - void syncFields(VariableHeightScrollable source) { - builder = source.builder; - if (token != source.token) - _contentsChanged = true; - token = source.token; - if (layoutState != source.layoutState) { - // Warning: this is unlikely to be what you intended. - assert(source.layoutState != null); - layoutState.removeListener(_handleLayoutChanged); - layoutState = source.layoutState; - layoutState.addListener(_handleLayoutChanged); - } - super.syncFields(source); - } - - ScrollBehavior createScrollBehavior() => new OverscrollBehavior(); - OverscrollBehavior get scrollBehavior => super.scrollBehavior; - - void _handleSizeChanged(Size newSize) { - scrollBehavior.containerSize = newSize.height; - } - - void _handleLayoutChanged() { - if (layoutState.didReachLastChild) { - scrollBehavior.contentsSize = layoutState.contentsSize; - if (_contentsChanged && scrollOffset > scrollBehavior.maxScrollOffset) { - _contentsChanged = false; - settleScrollOffset(); - } - } else { - scrollBehavior.contentsSize = double.INFINITY; - } - } - - Widget buildContent() { - return new SizeObserver( - callback: _handleSizeChanged, - child: new BlockViewport( - builder: builder, - layoutState: layoutState, - startOffset: scrollOffset, - token: token - ) - ); - } -}