mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Teach ScrollableBlock how to scroll horizontally
Now ScrollableBlock can combine a horizontally scrolling viewport with a horizontal block. Also rename ViewportScrollDirection to just ScrollDirection for less verbosity.
This commit is contained in:
parent
e68b15f468
commit
39b92bd2e9
59
sky/packages/sky/example/widgets/horizontal_scrolling.dart
Normal file
59
sky/packages/sky/example/widgets/horizontal_scrolling.dart
Normal file
@ -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<Widget> 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());
|
||||
}
|
||||
@ -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<RenderBox> {
|
||||
|
||||
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<RenderBox
|
||||
markNeedsPaint();
|
||||
}
|
||||
|
||||
ViewportScrollDirection _scrollDirection;
|
||||
ViewportScrollDirection get scrollDirection => _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<RenderBox
|
||||
BoxConstraints _getInnerConstraints(BoxConstraints constraints) {
|
||||
BoxConstraints innerConstraints;
|
||||
switch (scrollDirection) {
|
||||
case ViewportScrollDirection.both:
|
||||
case ScrollDirection.both:
|
||||
innerConstraints = new BoxConstraints();
|
||||
break;
|
||||
case ViewportScrollDirection.horizontal:
|
||||
case ScrollDirection.horizontal:
|
||||
innerConstraints = constraints.heightConstraints();
|
||||
break;
|
||||
case ViewportScrollDirection.vertical:
|
||||
case ScrollDirection.vertical:
|
||||
innerConstraints = constraints.widthConstraints();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -20,7 +20,8 @@ import 'package:sky/widgets/default_text_style.dart';
|
||||
import 'package:sky/widgets/framework.dart';
|
||||
|
||||
export 'package:sky/base/hit_test.dart' show EventDisposition, combineEventDispositions;
|
||||
export 'package:sky/rendering/box.dart' show BackgroundImage, BoxConstraints, BoxDecoration, Border, BorderSide, EdgeDims, ViewportScrollDirection;
|
||||
export 'package:sky/rendering/block.dart' show BlockDirection;
|
||||
export 'package:sky/rendering/box.dart' show BackgroundImage, BoxConstraints, BoxDecoration, Border, BorderSide, EdgeDims, ScrollDirection;
|
||||
export 'package:sky/rendering/flex.dart' show FlexDirection, FlexJustifyContent, FlexAlignItems;
|
||||
export 'package:sky/rendering/object.dart' show Point, Offset, Size, Rect, Color, Paint, Path;
|
||||
export 'package:sky/rendering/toggleable.dart' show ValueChanged;
|
||||
@ -271,12 +272,12 @@ class Viewport extends OneChildRenderObjectWrapper {
|
||||
Viewport({
|
||||
Key key,
|
||||
this.scrollOffset: Offset.zero,
|
||||
this.scrollDirection: ViewportScrollDirection.vertical,
|
||||
this.scrollDirection: ScrollDirection.vertical,
|
||||
Widget child
|
||||
}) : super(key: key, child: child);
|
||||
|
||||
final Offset scrollOffset;
|
||||
final ViewportScrollDirection scrollDirection;
|
||||
final ScrollDirection scrollDirection;
|
||||
|
||||
RenderViewport createNode() => 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<Widget> children, { Key key })
|
||||
: super(key: key, children: children);
|
||||
Block(List<Widget> 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) {
|
||||
|
||||
@ -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<Widget> 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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<TabLabel> labels;
|
||||
int selectedIndex;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user