Commit 1c3831e8 authored by Hans Muller's avatar Hans Muller

Merge pull request #1012 from HansMuller/improve-items-wrap

Restore PageableList itemsWrap:true

Makes PageableList with itemsWrap:true work again.

Plumbed the itemsWrap parameter through to HomogenousViewport.

Fixes issue #877.
parents b20bbd48 a69a95df
...@@ -16,6 +16,7 @@ class HomogeneousViewport extends RenderObjectWrapper { ...@@ -16,6 +16,7 @@ class HomogeneousViewport extends RenderObjectWrapper {
HomogeneousViewport({ HomogeneousViewport({
Key key, Key key,
this.builder, this.builder,
this.itemsWrap: false,
this.itemExtent, // required this.itemExtent, // required
this.itemCount, // optional, but you cannot shrink-wrap this class or otherwise use its intrinsic dimensions if you don't specify it this.itemCount, // optional, but you cannot shrink-wrap this class or otherwise use its intrinsic dimensions if you don't specify it
this.direction: ScrollDirection.vertical, this.direction: ScrollDirection.vertical,
...@@ -25,6 +26,7 @@ class HomogeneousViewport extends RenderObjectWrapper { ...@@ -25,6 +26,7 @@ class HomogeneousViewport extends RenderObjectWrapper {
} }
ListBuilder builder; ListBuilder builder;
bool itemsWrap;
double itemExtent; double itemExtent;
int itemCount; int itemCount;
ScrollDirection direction; ScrollDirection direction;
...@@ -115,16 +117,16 @@ class HomogeneousViewport extends RenderObjectWrapper { ...@@ -115,16 +117,16 @@ class HomogeneousViewport extends RenderObjectWrapper {
try { try {
double mainAxisExtent = direction == ScrollDirection.vertical ? constraints.maxHeight : constraints.maxWidth; double mainAxisExtent = direction == ScrollDirection.vertical ? constraints.maxHeight : constraints.maxWidth;
double offset; double offset;
if (startOffset <= 0.0) { if (startOffset <= 0.0 && !itemsWrap) {
_layoutFirstIndex = 0; _layoutFirstIndex = 0;
offset = -startOffset; offset = -startOffset;
} else { } else {
_layoutFirstIndex = startOffset ~/ itemExtent; _layoutFirstIndex = (startOffset / itemExtent).floor();
offset = -(startOffset % itemExtent); offset = -(startOffset % itemExtent);
} }
if (mainAxisExtent < double.INFINITY) { if (mainAxisExtent < double.INFINITY) {
_layoutItemCount = ((mainAxisExtent - offset) / itemExtent).ceil(); _layoutItemCount = ((mainAxisExtent - offset) / itemExtent).ceil();
if (itemCount != null) if (itemCount != null && !itemsWrap)
_layoutItemCount = math.min(_layoutItemCount, itemCount - _layoutFirstIndex); _layoutItemCount = math.min(_layoutItemCount, itemCount - _layoutFirstIndex);
} else { } else {
assert(() { assert(() {
......
...@@ -348,6 +348,7 @@ abstract class ScrollableWidgetList extends Scrollable { ...@@ -348,6 +348,7 @@ abstract class ScrollableWidgetList extends Scrollable {
Key key, Key key,
double initialScrollOffset, double initialScrollOffset,
ScrollDirection scrollDirection: ScrollDirection.vertical, ScrollDirection scrollDirection: ScrollDirection.vertical,
this.itemsWrap: false,
this.itemExtent, this.itemExtent,
this.padding this.padding
}) : super(key: key, initialScrollOffset: initialScrollOffset, scrollDirection: scrollDirection) { }) : super(key: key, initialScrollOffset: initialScrollOffset, scrollDirection: scrollDirection) {
...@@ -355,6 +356,7 @@ abstract class ScrollableWidgetList extends Scrollable { ...@@ -355,6 +356,7 @@ abstract class ScrollableWidgetList extends Scrollable {
} }
EdgeDims padding; EdgeDims padding;
bool itemsWrap;
double itemExtent; double itemExtent;
Size containerSize = Size.zero; Size containerSize = Size.zero;
...@@ -441,6 +443,7 @@ abstract class ScrollableWidgetList extends Scrollable { ...@@ -441,6 +443,7 @@ abstract class ScrollableWidgetList extends Scrollable {
padding: _crossAxisPadding, padding: _crossAxisPadding,
child: new HomogeneousViewport( child: new HomogeneousViewport(
builder: _buildItems, builder: _buildItems,
itemsWrap: itemsWrap,
itemExtent: itemExtent, itemExtent: itemExtent,
itemCount: itemCount, itemCount: itemCount,
direction: scrollDirection, direction: scrollDirection,
...@@ -472,19 +475,19 @@ class ScrollableList<T> extends ScrollableWidgetList { ...@@ -472,19 +475,19 @@ class ScrollableList<T> extends ScrollableWidgetList {
ScrollDirection scrollDirection: ScrollDirection.vertical, ScrollDirection scrollDirection: ScrollDirection.vertical,
this.items, this.items,
this.itemBuilder, this.itemBuilder,
this.itemsWrap: false, itemsWrap: false,
double itemExtent, double itemExtent,
EdgeDims padding EdgeDims padding
}) : super( }) : super(
key: key, key: key,
initialScrollOffset: initialScrollOffset, initialScrollOffset: initialScrollOffset,
scrollDirection: scrollDirection, scrollDirection: scrollDirection,
itemsWrap: itemsWrap,
itemExtent: itemExtent, itemExtent: itemExtent,
padding: padding); padding: padding);
List<T> items; List<T> items;
ItemBuilder<T> itemBuilder; ItemBuilder<T> itemBuilder;
bool itemsWrap;
void syncConstructorArguments(ScrollableList<T> source) { void syncConstructorArguments(ScrollableList<T> source) {
items = source.items; items = source.items;
...@@ -568,7 +571,7 @@ class PageableList<T> extends ScrollableList<T> { ...@@ -568,7 +571,7 @@ class PageableList<T> extends ScrollableList<T> {
return EventDisposition.processed; return EventDisposition.processed;
} }
int get currentPage => (scrollOffset / itemExtent).floor(); int get currentPage => (scrollOffset / itemExtent).floor() % itemCount;
void _notifyPageChanged(_) { void _notifyPageChanged(_) {
if (pageChanged != null) if (pageChanged != null)
......
...@@ -4,49 +4,89 @@ import 'package:test/test.dart'; ...@@ -4,49 +4,89 @@ import 'package:test/test.dart';
import 'widget_tester.dart'; import 'widget_tester.dart';
void main() { const Size pageSize = const Size(800.0, 600.0);
test('Scrolling changes page', () { const List<int> pages = const <int>[0, 1, 2, 3, 4, 5];
WidgetTester tester = new WidgetTester(); int currentPage = null;
List<int> pages = [0, 1, 2, 3, 4, 5];
Size pageSize = new Size(200.0, 200.0);
int currentPage;
Widget buildPage(int page) { Widget buildPage(int page) {
return new Container( return new Container(
key: new ValueKey<int>(page), key: new ValueKey<int>(page),
width: pageSize.width, width: pageSize.width,
height: pageSize.height, height: pageSize.height,
child: new Text(page.toString()) child: new Text(page.toString())
); );
} }
Widget builder() { Widget buildFrame({ bool itemsWrap: false }) {
return new Container( // The test framework forces the frame (and so the PageableList)
height: pageSize.height, // to be 800x600. The pageSize constant reflects as much.
child: new PageableList<int>( return new PageableList<int>(
padding: new EdgeDims.symmetric(horizontal: 10.0),
items: pages, items: pages,
itemBuilder: buildPage, itemBuilder: buildPage,
scrollDirection: ScrollDirection.horizontal, itemsWrap: itemsWrap,
itemExtent: pageSize.width, itemExtent: pageSize.width,
pageChanged: (int page) { scrollDirection: ScrollDirection.horizontal,
currentPage = page; pageChanged: (int page) { currentPage = page; }
}
)
); );
} }
tester.pumpFrame(builder);
expect(currentPage, isNull); void page(WidgetTester tester, Offset offset) {
String itemText = currentPage != null ? currentPage.toString() : '0';
new FakeAsync().run((async) { new FakeAsync().run((async) {
tester.scroll(tester.findText('1'), new Offset(-300.0, 0.0)); tester.scroll(tester.findText(itemText), offset);
// One frame to start the animation, a second to complete it. // One frame to start the animation, a second to complete it.
tester.pumpFrame(builder); tester.pumpFrame(buildFrame);
tester.pumpFrame(builder, 5000.0); tester.pumpFrame(buildFrame, 1000.0);
async.elapse(new Duration(seconds: 5)); async.elapse(new Duration(seconds: 1));
expect(currentPage, equals(2)); });
}
void pageLeft(WidgetTester tester) {
page(tester, new Offset(-pageSize.width, 0.0));
}
void pageRight(WidgetTester tester) {
page(tester, new Offset(pageSize.width, 0.0));
}
void main() {
// PageableList with itemsWrap: false
test('Scroll left from page 0 to page 1', () {
WidgetTester tester = new WidgetTester();
currentPage = null;
tester.pumpFrame(buildFrame);
expect(currentPage, isNull);
pageLeft(tester);
expect(currentPage, equals(1));
});
test('Underscroll (scroll right), return to page 0', () {
WidgetTester tester = new WidgetTester();
currentPage = null;
tester.pumpFrame(buildFrame);
expect(currentPage, isNull);
pageRight(tester);
expect(currentPage, equals(0));
}); });
// PageableList with itemsWrap: true
test('Scroll left page 0 to page 1, itemsWrap: true', () {
WidgetTester tester = new WidgetTester();
currentPage = null;
tester.pumpFrame(() { return buildFrame(itemsWrap: true); });
expect(currentPage, isNull);
pageLeft(tester);
expect(currentPage, equals(1));
});
test('Scroll right from page 0 to page 5, itemsWrap: true', () {
WidgetTester tester = new WidgetTester();
currentPage = null;
tester.pumpFrame(() { return buildFrame(itemsWrap: true); });
expect(currentPage, isNull);
pageRight(tester);
expect(currentPage, equals(5));
}); });
} }
...@@ -117,8 +117,10 @@ class WidgetTester { ...@@ -117,8 +117,10 @@ class WidgetTester {
void scroll(Widget widget, Offset offset, { int pointer: 1 }) { void scroll(Widget widget, Offset offset, { int pointer: 1 }) {
Point startLocation = getCenter(widget); Point startLocation = getCenter(widget);
Point endLocation = startLocation + offset; Point endLocation = startLocation + offset;
HitTestResult result = _hitTest(startLocation);
TestPointer p = new TestPointer(pointer); TestPointer p = new TestPointer(pointer);
// Events for the entire press-drag-release gesture are dispatched
// to the widgets "hit" by the pointer down event.
HitTestResult result = _hitTest(startLocation);
_dispatchEvent(p.down(startLocation), result); _dispatchEvent(p.down(startLocation), result);
_dispatchEvent(p.move(endLocation), result); _dispatchEvent(p.move(endLocation), result);
_dispatchEvent(p.up(), result); _dispatchEvent(p.up(), result);
......
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