diff --git a/sky/packages/sky/example/widgets/horizontal_scrolling.dart b/sky/packages/sky/example/widgets/horizontal_scrolling.dart new file mode 100644 index 00000000000..0b344e21c27 --- /dev/null +++ b/sky/packages/sky/example/widgets/horizontal_scrolling.dart @@ -0,0 +1,59 @@ +// 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/painting/box_painter.dart'; +import 'package:sky/widgets.dart'; + +class Circle extends Component { + Widget build() { + return new Container( + width: 50.0, + margin: new EdgeDims.symmetric(horizontal: 2.0), + decoration: new BoxDecoration( + shape: Shape.circle, + backgroundColor: const Color(0xFF00FF00) + ) + ); + } +} + +class Pad extends Component { + Widget build() { + return new SizedBox(width: 10.0); + } +} + +class HorizontalScrollingApp extends App { + Widget build() { + List circles = [ + new Pad(), + new Circle(), + new Circle(), + new Circle(), + new Circle(), + new Circle(), + new Circle(), + new Circle(), + new Circle(), + new Circle(), + new Circle(), + new Circle(), + new Circle(), + new Pad(), + ]; + + return new Center( + child: new Container( + height: 50.0, + child: new Flex([ + new ScrollableBlock(circles, scrollDirection: ScrollDirection.horizontal) + ], justifyContent: FlexJustifyContent.end) + ) + ); + } +} + +void main() { + runApp(new HorizontalScrollingApp()); +} diff --git a/sky/packages/sky/lib/rendering/box.dart b/sky/packages/sky/lib/rendering/box.dart index abac4aeeb18..6aa5dab5725 100644 --- a/sky/packages/sky/lib/rendering/box.dart +++ b/sky/packages/sky/lib/rendering/box.dart @@ -1121,27 +1121,27 @@ class RenderBaseline extends RenderShiftedBox { String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}baseline: ${baseline}\nbaselineType: ${baselineType}'; } -enum ViewportScrollDirection { horizontal, vertical, both } +enum ScrollDirection { horizontal, vertical, both } class RenderViewport extends RenderBox with RenderObjectWithChildMixin { RenderViewport({ RenderBox child, Offset scrollOffset, - ViewportScrollDirection scrollDirection: ViewportScrollDirection.vertical + ScrollDirection scrollDirection: ScrollDirection.vertical }) : _scrollOffset = scrollOffset, _scrollDirection = scrollDirection { assert(_offsetIsSane(scrollOffset, scrollDirection)); this.child = child; } - bool _offsetIsSane(Offset offset, ViewportScrollDirection direction) { + bool _offsetIsSane(Offset offset, ScrollDirection direction) { switch (direction) { - case ViewportScrollDirection.both: + case ScrollDirection.both: return true; - case ViewportScrollDirection.horizontal: + case ScrollDirection.horizontal: return offset.dy == 0.0; - case ViewportScrollDirection.vertical: + case ScrollDirection.vertical: return offset.dx == 0.0; } } @@ -1156,9 +1156,9 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin _scrollDirection; - void set scrollDirection(ViewportScrollDirection value) { + ScrollDirection _scrollDirection; + ScrollDirection get scrollDirection => _scrollDirection; + void set scrollDirection(ScrollDirection value) { if (value == _scrollDirection) return; assert(_offsetIsSane(scrollOffset, value)); @@ -1169,13 +1169,13 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin new RenderViewport(scrollOffset: scrollOffset, scrollDirection: scrollDirection); RenderViewport get root => super.root; @@ -371,11 +372,20 @@ class Container extends Component { // LAYOUT NODES class Block extends MultiChildRenderObjectWrapper { - Block(List children, { Key key }) - : super(key: key, children: children); + Block(List children, { + Key key, + this.direction: BlockDirection.vertical + }) : super(key: key, children: children); - RenderBlock createNode() => new RenderBlock(); + final BlockDirection direction; + + RenderBlock createNode() => new RenderBlock(direction: direction); RenderBlock get root => super.root; + + void syncRenderObject(Widget old) { + super.syncRenderObject(old); + root.direction = direction; + } } class Stack extends MultiChildRenderObjectWrapper { @@ -417,7 +427,7 @@ class Flex extends MultiChildRenderObjectWrapper { final FlexAlignItems alignItems; final TextBaseline textBaseline; - RenderFlex createNode() => new RenderFlex(direction: this.direction); + RenderFlex createNode() => new RenderFlex(direction: direction); RenderFlex get root => super.root; void syncRenderObject(Widget old) { diff --git a/sky/packages/sky/lib/widgets/scrollable.dart b/sky/packages/sky/lib/widgets/scrollable.dart index 2a8340ecaad..2108ce0cd5e 100644 --- a/sky/packages/sky/lib/widgets/scrollable.dart +++ b/sky/packages/sky/lib/widgets/scrollable.dart @@ -37,13 +37,13 @@ abstract class Scrollable extends StatefulComponent { Scrollable({ Key key, - this.scrollDirection: ViewportScrollDirection.vertical + this.scrollDirection: ScrollDirection.vertical }) : super(key: key) { - assert(scrollDirection == ViewportScrollDirection.vertical || - scrollDirection == ViewportScrollDirection.horizontal); + assert(scrollDirection == ScrollDirection.vertical || + scrollDirection == ScrollDirection.horizontal); } - ViewportScrollDirection scrollDirection; + ScrollDirection scrollDirection; AnimatedSimulation _toEndAnimation; // See _startToEndAnimation() AnimationPerformance _toOffsetAnimation; // Started by scrollTo(offset, duration: d) @@ -65,7 +65,7 @@ abstract class Scrollable extends StatefulComponent { double get scrollOffset => _scrollOffset; Offset get scrollOffsetVector { - if (scrollDirection == ViewportScrollDirection.horizontal) + if (scrollDirection == ScrollDirection.horizontal) return new Offset(scrollOffset, 0.0); return new Offset(0.0, scrollOffset); } @@ -176,7 +176,7 @@ abstract class Scrollable extends StatefulComponent { } bool scrollBy(double scrollDelta) { - var newScrollOffset = scrollBehavior.applyCurve(_scrollOffset, scrollDelta); + double newScrollOffset = scrollBehavior.applyCurve(_scrollOffset, scrollDelta); return scrollTo(newScrollOffset); } @@ -195,12 +195,12 @@ abstract class Scrollable extends StatefulComponent { } EventDisposition _handleScrollUpdate(sky.GestureEvent event) { - scrollBy(scrollDirection == ViewportScrollDirection.horizontal ? event.dx : -event.dy); + scrollBy(scrollDirection == ScrollDirection.horizontal ? event.dx : -event.dy); return EventDisposition.processed; } EventDisposition _handleFlingStart(sky.GestureEvent event) { - double eventVelocity = scrollDirection == ViewportScrollDirection.horizontal + double eventVelocity = scrollDirection == ScrollDirection.horizontal ? -event.velocityX : -event.velocityY; _startToEndAnimation(velocity: _velocityForFlingGesture(eventVelocity)); @@ -235,7 +235,7 @@ class ScrollableViewport extends Scrollable { ScrollableViewport({ Key key, this.child, - ViewportScrollDirection scrollDirection: ViewportScrollDirection.vertical + ScrollDirection scrollDirection: ScrollDirection.vertical }) : super(key: key, scrollDirection: scrollDirection); Widget child; @@ -248,19 +248,19 @@ class ScrollableViewport extends Scrollable { ScrollBehavior createScrollBehavior() => new OverscrollWhenScrollableBehavior(); OverscrollWhenScrollableBehavior get scrollBehavior => super.scrollBehavior; - double _viewportHeight = 0.0; - double _childHeight = 0.0; + double _viewportSize = 0.0; + double _childSize = 0.0; void _handleViewportSizeChanged(Size newSize) { - _viewportHeight = newSize.height; + _viewportSize = scrollDirection == ScrollDirection.vertical ? newSize.height : newSize.width; _updateScrollBehaviour(); } void _handleChildSizeChanged(Size newSize) { - _childHeight = newSize.height; + _childSize = scrollDirection == ScrollDirection.vertical ? newSize.height : newSize.width; _updateScrollBehaviour(); } void _updateScrollBehaviour() { - scrollBehavior.contentsSize = _childHeight; - scrollBehavior.containerSize = _viewportHeight; + scrollBehavior.contentsSize = _childSize; + scrollBehavior.containerSize = _viewportSize; if (scrollOffset > scrollBehavior.maxScrollOffset) settleScrollOffset(); } @@ -284,13 +284,24 @@ class ScrollableViewport extends Scrollable { /// 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); + ScrollableBlock(this.children, { + Key key, + this.scrollDirection: ScrollDirection.vertical + }) : super(key: key); final List children; + final ScrollDirection scrollDirection; + + BlockDirection get _direction { + if (scrollDirection == ScrollDirection.vertical) + return BlockDirection.vertical; + return BlockDirection.horizontal; + } Widget build() { return new ScrollableViewport( - child: new Block(children) + scrollDirection: scrollDirection, + child: new Block(children, direction: _direction) ); } } diff --git a/sky/packages/sky/lib/widgets/tabs.dart b/sky/packages/sky/lib/widgets/tabs.dart index 974723a861f..2cb2f4ee37d 100644 --- a/sky/packages/sky/lib/widgets/tabs.dart +++ b/sky/packages/sky/lib/widgets/tabs.dart @@ -396,7 +396,7 @@ class TabBar extends Scrollable { this.selectedIndex: 0, this.onChanged, this.isScrollable: false - }) : super(key: key, scrollDirection: ViewportScrollDirection.horizontal); + }) : super(key: key, scrollDirection: ScrollDirection.horizontal); Iterable labels; int selectedIndex;