Commit bec3fdef authored by Hans Muller's avatar Hans Muller

Add a Scrollable builder, refactor ScrollableList, et al (#3950)

* Add a Scrollable builder, refactor ScrollableList, et al

* Add space between the dialog demo buttons

* removed vestigial code
parent 0e8f26dd
......@@ -197,6 +197,14 @@ class DialogDemoState extends State<DialogDemo> {
}
)
]
// Add a little space between the buttons
.map((Widget button) {
return new Container(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: button
);
})
.toList()
)
);
}
......
......@@ -130,74 +130,109 @@ class LazyBlockChildren extends LazyBlockDelegate {
/// Prefer [ScrollableList] when all the children have the same height because
/// it can use that property to be more efficient. Prefer [ScrollableViewport]
/// when there is only one child.
class LazyBlock extends Scrollable {
class LazyBlock extends StatelessWidget {
LazyBlock({
Key key,
double initialScrollOffset,
Axis scrollDirection: Axis.vertical,
ScrollListener onScrollStart,
ScrollListener onScroll,
ScrollListener onScrollEnd,
SnapOffsetCallback snapOffsetCallback,
this.delegate,
this.padding
}) : super(
key: key,
initialScrollOffset: initialScrollOffset,
scrollDirection: scrollDirection,
onScrollStart: onScrollStart,
onScroll: onScroll,
onScrollEnd: onScrollEnd,
snapOffsetCallback: snapOffsetCallback
);
this.initialScrollOffset,
this.scrollDirection: Axis.vertical,
this.onScrollStart,
this.onScroll,
this.onScrollEnd,
this.snapOffsetCallback,
this.scrollableKey,
this.padding,
this.delegate
}) : super(key: key);
/// Provides children for this widget.
/// The scroll offset this widget should use when first created.
final double initialScrollOffset;
/// The axis along which this widget should scroll.
final Axis scrollDirection;
/// Called whenever this widget starts to scroll.
final ScrollListener onScrollStart;
/// Called whenever this widget's scroll offset changes.
final ScrollListener onScroll;
/// Called whenever this widget stops scrolling.
final ScrollListener onScrollEnd;
/// Called to determine the offset to which scrolling should snap,
/// when handling a fling.
///
/// See [LazyBlockDelegate] for details.
final LazyBlockDelegate delegate;
/// This callback, if set, will be called with the offset that the
/// Scrollable would have scrolled to in the absence of this
/// callback, and a Size describing the size of the Scrollable
/// itself.
///
/// The callback's return value is used as the new scroll offset to
/// aim for.
///
/// If the callback simply returns its first argument (the offset),
/// then it is as if the callback was null.
final SnapOffsetCallback snapOffsetCallback;
/// The key for the Scrollable created by this widget.
final Key scrollableKey;
/// The amount of space by which to inset the children inside the viewport.
final EdgeInsets padding;
@override
ScrollableState<LazyBlock> createState() => new _LazyBlockState();
}
class _LazyBlockState extends ScrollableState<LazyBlock> {
@override
BoundedBehavior createScrollBehavior() => new OverscrollWhenScrollableBehavior();
@override
BoundedBehavior get scrollBehavior => super.scrollBehavior;
/// Provides children for this widget.
///
/// See [LazyBlockDelegate] for details.
final LazyBlockDelegate delegate;
void _handleExtentsChanged(double contentExtent, double containerExtent, double minScrollOffset) {
setState(() {
didUpdateScrollBehavior(scrollBehavior.updateExtents(
void _handleExtentsChanged(
ScrollableState state,
double contentExtent,
double containerExtent,
double minScrollOffset) {
state.setState(() {
final BoundedBehavior scrollBehavior = state.scrollBehavior;
state.didUpdateScrollBehavior(scrollBehavior.updateExtents(
contentExtent: contentExtent,
containerExtent: containerExtent,
minScrollOffset: minScrollOffset,
scrollOffset: scrollOffset
scrollOffset: state.scrollOffset
));
});
}
@override
Widget buildContent(BuildContext context) {
Widget _buildContent(BuildContext context, ScrollableState state) {
final bool clampOverscrolls = ClampOverscrolls.of(context);
final double startOffset = clampOverscrolls
? scrollOffset.clamp(scrollBehavior.minScrollOffset, scrollBehavior.maxScrollOffset)
: scrollOffset;
? state.scrollOffset.clamp(state.scrollBehavior.minScrollOffset, state.scrollBehavior.maxScrollOffset)
: state.scrollOffset;
Widget viewport = new LazyBlockViewport(
startOffset: startOffset,
mainAxis: config.scrollDirection,
padding: config.padding,
onExtentsChanged: _handleExtentsChanged,
delegate: config.delegate
mainAxis: scrollDirection,
padding: padding,
onExtentsChanged: (double contentExtent, double containerExtent, double minScrollOffset) {
_handleExtentsChanged(state, contentExtent, containerExtent, minScrollOffset);
},
delegate: delegate
);
if (clampOverscrolls)
viewport = new ClampOverscrolls(value: false, child: viewport);
return viewport;
}
@override
Widget build(BuildContext context) {
return new Scrollable(
key: scrollableKey,
initialScrollOffset: initialScrollOffset,
scrollDirection: scrollDirection,
onScrollStart: onScrollStart,
onScroll: onScroll,
onScrollEnd: onScrollEnd,
snapOffsetCallback: snapOffsetCallback,
builder: _buildContent
);
}
}
/// Signature used by [LazyBlockViewport] to report its interior and exterior dimensions.
......
......@@ -8,67 +8,93 @@ import 'package:collection/collection.dart' show lowerBound;
import 'package:flutter/rendering.dart';
import 'framework.dart';
import 'scroll_behavior.dart';
import 'scrollable.dart';
import 'virtual_viewport.dart';
/// A vertically scrollable grid.
///
/// Requires that delegate places its children in row-major order.
class ScrollableGrid extends Scrollable {
class ScrollableGrid extends StatelessWidget {
ScrollableGrid({
Key key,
double initialScrollOffset,
ScrollListener onScrollStart,
ScrollListener onScroll,
ScrollListener onScrollEnd,
SnapOffsetCallback snapOffsetCallback,
this.initialScrollOffset,
this.onScrollStart,
this.onScroll,
this.onScrollEnd,
this.snapOffsetCallback,
this.scrollableKey,
this.delegate,
this.children
}) : super(
key: key,
initialScrollOffset: initialScrollOffset,
// TODO(abarth): Support horizontal offsets. For horizontally scrolling
// grids. For horizontally scrolling grids, we'll probably need to use a
// delegate that places children in column-major order.
scrollDirection: Axis.vertical,
onScrollStart: onScrollStart,
onScroll: onScroll,
onScrollEnd: onScrollEnd,
snapOffsetCallback: snapOffsetCallback
);
}) : super(key: key);
/// The scroll offset this widget should use when first created.
final double initialScrollOffset;
/// Called whenever this widget starts to scroll.
final ScrollListener onScrollStart;
/// Called whenever this widget's scroll offset changes.
final ScrollListener onScroll;
/// Called whenever this widget stops scrolling.
final ScrollListener onScrollEnd;
/// Called to determine the offset to which scrolling should snap,
/// when handling a fling.
///
/// This callback, if set, will be called with the offset that the
/// Scrollable would have scrolled to in the absence of this
/// callback, and a Size describing the size of the Scrollable
/// itself.
///
/// The callback's return value is used as the new scroll offset to
/// aim for.
///
/// If the callback simply returns its first argument (the offset),
/// then it is as if the callback was null.
final SnapOffsetCallback snapOffsetCallback;
/// The key for the Scrollable created by this widget.
final Key scrollableKey;
final GridDelegate delegate;
final Iterable<Widget> children;
@override
ScrollableState createState() => new _ScrollableGridState();
}
class _ScrollableGridState extends ScrollableState<ScrollableGrid> {
@override
ExtentScrollBehavior createScrollBehavior() => new OverscrollBehavior();
@override
ExtentScrollBehavior get scrollBehavior => super.scrollBehavior;
void _handleExtentsChanged(double contentExtent, double containerExtent) {
setState(() {
didUpdateScrollBehavior(scrollBehavior.updateExtents(
void _handleExtentsChanged(ScrollableState state, double contentExtent, double containerExtent) {
state.setState(() {
state.didUpdateScrollBehavior(state.scrollBehavior.updateExtents(
contentExtent: contentExtent,
containerExtent: containerExtent,
scrollOffset: scrollOffset
scrollOffset: state.scrollOffset
));
});
}
@override
Widget buildContent(BuildContext context) {
Widget _buildContent(BuildContext context, ScrollableState state) {
return new GridViewport(
startOffset: scrollOffset,
delegate: config.delegate,
onExtentsChanged: _handleExtentsChanged,
children: config.children
startOffset: state.scrollOffset,
delegate: delegate,
onExtentsChanged: (double contentExtent, double containerExtent) {
_handleExtentsChanged(state, contentExtent, containerExtent);
},
children: children
);
}
@override
Widget build(BuildContext context) {
return new Scrollable(
key: scrollableKey,
initialScrollOffset: initialScrollOffset,
// TODO(abarth): Support horizontal offsets. For horizontally scrolling
// grids. For horizontally scrolling grids, we'll probably need to use a
// delegate that places children in column-major order.
scrollDirection: Axis.vertical,
onScrollStart: onScrollStart,
onScroll: onScroll,
onScrollEnd: onScrollEnd,
snapOffsetCallback: snapOffsetCallback,
builder: _buildContent
);
}
}
......
......@@ -46,7 +46,7 @@ void main() {
expect(find.text('10'), findsNothing);
expect(find.text('100'), findsNothing);
ScrollableState targetState = tester.state(find.byType(ScrollableLazyList));
ScrollableState targetState = tester.state(find.byType(Scrollable));
targetState.scrollTo(1000.0);
await tester.pump(new Duration(seconds: 1));
......
......@@ -7,7 +7,7 @@ import 'package:flutter/widgets.dart';
Widget _buildScroller({Key key, List<String> log}) {
return new ScrollableViewport(
key: key,
scrollableKey: key,
onScrollStart: (double scrollOffset) {
log.add('scrollstart');
},
......
......@@ -13,8 +13,8 @@ void main() {
]
));
ScrollableState<ScrollableViewport> scrollable =
tester.state/*<ScrollableState<ScrollableViewport>>*/(find.byType(ScrollableViewport));
ScrollableState scrollable =
tester.state/*<ScrollableState>*/(find.byType(Scrollable));
expect(scrollable.scrollOffset, equals(0.0));
......
......@@ -75,10 +75,10 @@ void main() {
return result;
};
GlobalKey<ScrollableState<ScrollableLazyList>> scrollableKey = new GlobalKey<ScrollableState<ScrollableLazyList>>();
GlobalKey<ScrollableState> scrollableKey = new GlobalKey<ScrollableState>();
FlipWidget testWidget = new FlipWidget(
left: new ScrollableLazyList(
key: scrollableKey,
scrollableKey: scrollableKey,
itemBuilder: itemBuilder,
itemExtent: 200.0,
initialScrollOffset: 300.0
......@@ -123,10 +123,10 @@ void main() {
return result;
};
GlobalKey<ScrollableState<ScrollableLazyList>> scrollableKey = new GlobalKey<ScrollableState<ScrollableLazyList>>();
GlobalKey<ScrollableState> scrollableKey = new GlobalKey<ScrollableState>();
FlipWidget testWidget = new FlipWidget(
left: new ScrollableLazyList(
key: scrollableKey,
scrollableKey: scrollableKey,
itemBuilder: itemBuilder,
itemExtent: 200.0,
initialScrollOffset: 300.0,
......@@ -167,9 +167,9 @@ void main() {
return result;
};
GlobalKey<ScrollableState<ScrollableLazyList>> scrollableKey = new GlobalKey<ScrollableState<ScrollableLazyList>>();
GlobalKey<ScrollableState> scrollableKey = new GlobalKey<ScrollableState>();
Widget testWidget = new ScrollableLazyList(
key: scrollableKey,
scrollableKey: scrollableKey,
itemBuilder: itemBuilder,
itemExtent: 300.0,
itemCount: 10
......
......@@ -29,7 +29,7 @@ Widget buildFrame() {
child: new Container(
height: itemExtent * 2.0,
child: new ScrollableList(
key: scrollableListKey,
scrollableKey: scrollableListKey,
snapOffsetCallback: snapOffsetCallback,
scrollDirection: scrollDirection,
itemExtent: itemExtent,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment