Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
4ba5e712
Commit
4ba5e712
authored
Feb 10, 2016
by
Adam Barth
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Teach PageableList about scroll anchors
parent
b07203a8
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
164 additions
and
46 deletions
+164
-46
pageable_list.dart
packages/flutter/lib/src/widgets/pageable_list.dart
+69
-31
pageable_list_test.dart
packages/flutter/test/widget/pageable_list_test.dart
+95
-15
No files found.
packages/flutter/lib/src/widgets/pageable_list.dart
View file @
4ba5e712
...
...
@@ -19,13 +19,12 @@ enum ItemsSnapAlignment {
adjacentItem
}
typedef
void
PageChangedCallback
(
int
newPage
);
class
PageableList
extends
Scrollable
{
PageableList
({
Key
key
,
initialScrollOffset
,
double
initialScrollOffset
,
Axis
scrollDirection:
Axis
.
vertical
,
ViewportAnchor
scrollAnchor:
ViewportAnchor
.
start
,
ScrollListener
onScrollStart
,
ScrollListener
onScroll
,
ScrollListener
onScrollEnd
,
...
...
@@ -42,6 +41,7 @@ class PageableList extends Scrollable {
key:
key
,
initialScrollOffset:
initialScrollOffset
,
scrollDirection:
scrollDirection
,
scrollAnchor:
scrollAnchor
,
onScrollStart:
onScrollStart
,
onScroll:
onScroll
,
onScrollEnd:
onScrollEnd
,
...
...
@@ -51,7 +51,7 @@ class PageableList extends Scrollable {
final
bool
itemsWrap
;
final
ItemsSnapAlignment
itemsSnapAlignment
;
final
PageChangedCallback
onPageChanged
;
final
ValueChanged
<
int
>
onPageChanged
;
final
ScrollableListPainter
scrollableListPainter
;
final
Duration
duration
;
final
Curve
curve
;
...
...
@@ -61,7 +61,7 @@ class PageableList extends Scrollable {
}
class
PageableListState
<
T
extends
PageableList
>
extends
ScrollableState
<
T
>
{
int
get
itemCount
=>
config
.
children
?.
length
??
0
;
int
get
_
itemCount
=>
config
.
children
?.
length
??
0
;
int
_previousItemCount
;
double
get
_pixelsPerScrollUnit
{
...
...
@@ -85,6 +85,19 @@ class PageableListState<T extends PageableList> extends ScrollableState<T> {
return
super
.
scrollOffsetToPixelOffset
(
scrollOffset
*
_pixelsPerScrollUnit
);
}
int
_scrollOffsetToPageIndex
(
double
scrollOffset
)
{
int
itemCount
=
_itemCount
;
if
(
itemCount
==
0
)
return
0
;
int
scrollIndex
=
scrollOffset
.
floor
();
switch
(
config
.
scrollAnchor
)
{
case
ViewportAnchor
.
start
:
return
scrollIndex
%
itemCount
;
case
ViewportAnchor
.
end
:
return
(
_itemCount
-
scrollIndex
-
1
)
%
itemCount
;
}
}
void
initState
()
{
super
.
initState
();
_updateScrollBehavior
();
...
...
@@ -98,8 +111,8 @@ class PageableListState<T extends PageableList> extends ScrollableState<T> {
if
(
config
.
itemsWrap
!=
oldConfig
.
itemsWrap
)
scrollBehaviorUpdateNeeded
=
true
;
if
(
itemCount
!=
_previousItemCount
)
{
_previousItemCount
=
itemCount
;
if
(
_
itemCount
!=
_previousItemCount
)
{
_previousItemCount
=
_
itemCount
;
scrollBehaviorUpdateNeeded
=
true
;
}
...
...
@@ -108,9 +121,9 @@ class PageableListState<T extends PageableList> extends ScrollableState<T> {
}
void
_updateScrollBehavior
()
{
config
.
scrollableListPainter
?.
contentExtent
=
itemCount
.
toDouble
();
config
.
scrollableListPainter
?.
contentExtent
=
_
itemCount
.
toDouble
();
scrollTo
(
scrollBehavior
.
updateExtents
(
contentExtent:
itemCount
.
toDouble
(),
contentExtent:
_
itemCount
.
toDouble
(),
containerExtent:
1.0
,
scrollOffset:
scrollOffset
));
...
...
@@ -135,6 +148,7 @@ class PageableListState<T extends PageableList> extends ScrollableState<T> {
return
new
PageViewport
(
itemsWrap:
config
.
itemsWrap
,
scrollDirection:
config
.
scrollDirection
,
scrollAnchor:
config
.
scrollAnchor
,
startOffset:
scrollOffset
,
overlayPainter:
config
.
scrollableListPainter
,
children:
config
.
children
...
...
@@ -187,7 +201,7 @@ class PageableListState<T extends PageableList> extends ScrollableState<T> {
void
_notifyPageChanged
(
_
)
{
if
(
config
.
onPageChanged
!=
null
)
config
.
onPageChanged
(
itemCount
==
0
?
0
:
scrollOffset
.
floor
()
%
itemCount
);
config
.
onPageChanged
(
_scrollOffsetToPageIndex
(
scrollOffset
)
);
}
}
...
...
@@ -195,6 +209,7 @@ class PageViewport extends VirtualViewport with VirtualViewportIterableMixin {
PageViewport
({
this
.
startOffset
:
0.0
,
this
.
scrollDirection
:
Axis
.
vertical
,
this
.
scrollAnchor
:
ViewportAnchor
.
start
,
this
.
itemsWrap
:
false
,
this
.
overlayPainter
,
this
.
children
...
...
@@ -204,6 +219,7 @@ class PageViewport extends VirtualViewport with VirtualViewportIterableMixin {
final
double
startOffset
;
final
Axis
scrollDirection
;
final
ViewportAnchor
scrollAnchor
;
final
bool
itemsWrap
;
final
Painter
overlayPainter
;
final
Iterable
<
Widget
>
children
;
...
...
@@ -224,11 +240,11 @@ class _PageViewportElement extends VirtualViewportElement<PageViewport> {
int
get
materializedChildCount
=>
_materializedChildCount
;
int
_materializedChildCount
;
double
get
startOffsetBase
=>
_
repain
tOffsetBase
;
double
_
repain
tOffsetBase
;
double
get
startOffsetBase
=>
_
star
tOffsetBase
;
double
_
star
tOffsetBase
;
double
get
startOffsetLimit
=>
_
repain
tOffsetLimit
;
double
_
repain
tOffsetLimit
;
double
get
startOffsetLimit
=>
_
star
tOffsetLimit
;
double
_
star
tOffsetLimit
;
double
scrollOffsetToPixelOffset
(
double
scrollOffset
)
{
if
(
_containerExtent
==
null
)
...
...
@@ -245,34 +261,56 @@ class _PageViewportElement extends VirtualViewportElement<PageViewport> {
double
_containerExtent
;
double
_getContainerExtentFromRenderObject
()
{
void
_updateViewportDimensions
()
{
final
Size
containerSize
=
renderObject
.
size
;
Size
materializedContentSize
;
switch
(
widget
.
scrollDirection
)
{
case
Axis
.
vertical
:
return
renderObject
.
size
.
height
;
materializedContentSize
=
new
Size
(
containerSize
.
width
,
_materializedChildCount
*
containerSize
.
height
);
break
;
case
Axis
.
horizontal
:
return
renderObject
.
size
.
width
;
materializedContentSize
=
new
Size
(
_materializedChildCount
*
containerSize
.
width
,
containerSize
.
height
);
break
;
}
renderObject
.
dimensions
=
new
ViewportDimensions
(
containerSize:
containerSize
,
contentSize:
materializedContentSize
);
}
void
layout
(
BoxConstraints
constraints
)
{
int
length
=
renderObject
.
virtualChildCount
;
_containerExtent
=
_getContainerExtentFromRenderObject
();
_materializedChildBase
=
widget
.
startOffset
.
floor
();
int
materializedChildLimit
=
(
widget
.
startOffset
+
1.0
).
ceil
();
final
int
length
=
renderObject
.
virtualChildCount
;
if
(!
widget
.
itemsWrap
)
{
_materializedChildBase
=
_materializedChildBase
.
clamp
(
0
,
length
);
materializedChildLimit
=
materializedChildLimit
.
clamp
(
0
,
length
);
}
else
if
(
length
==
0
)
{
materializedChildLimit
=
_materializedChildBase
;
switch
(
widget
.
scrollDirection
)
{
case
Axis
.
vertical
:
_containerExtent
=
renderObject
.
size
.
height
;
break
;
case
Axis
.
horizontal
:
_containerExtent
=
renderObject
.
size
.
width
;
break
;
}
_materializedChildCount
=
materializedChildLimit
-
_materializedChildBase
;
_repaintOffsetBase
=
_materializedChildBase
.
toDouble
();
_repaintOffsetLimit
=
(
materializedChildLimit
-
1
).
toDouble
();
if
(
length
==
0
)
{
_materializedChildBase
=
0
;
_materializedChildCount
=
0
;
_startOffsetBase
=
0.0
;
_startOffsetLimit
=
double
.
INFINITY
;
}
else
{
int
startItem
=
widget
.
startOffset
.
floor
();
int
limitItem
=
(
widget
.
startOffset
+
1.0
).
ceil
();
if
(!
widget
.
itemsWrap
)
{
startItem
=
startItem
.
clamp
(
0
,
length
);
limitItem
=
limitItem
.
clamp
(
0
,
length
);
}
_materializedChildBase
=
startItem
;
_materializedChildCount
=
limitItem
-
startItem
;
_startOffsetBase
=
startItem
.
toDouble
();
_startOffsetLimit
=
(
limitItem
-
1
).
toDouble
();
if
(
widget
.
scrollAnchor
==
ViewportAnchor
.
end
)
_materializedChildBase
=
(
length
-
_materializedChildBase
-
_materializedChildCount
)
%
length
;
}
_updateViewportDimensions
();
super
.
layout
(
constraints
);
}
}
packages/flutter/test/widget/pageable_list_test.dart
View file @
4ba5e712
...
...
@@ -11,7 +11,6 @@ Size pageSize = new Size(600.0, 300.0);
const
List
<
int
>
defaultPages
=
const
<
int
>[
0
,
1
,
2
,
3
,
4
,
5
];
final
List
<
GlobalKey
>
globalKeys
=
defaultPages
.
map
((
_
)
=>
new
GlobalKey
()).
toList
();
int
currentPage
=
null
;
bool
itemsWrap
=
false
;
Widget
buildPage
(
int
page
)
{
return
new
Container
(
...
...
@@ -22,11 +21,16 @@ Widget buildPage(int page) {
);
}
Widget
buildFrame
(
{
List
<
int
>
pages:
defaultPages
})
{
final
list
=
new
PageableList
(
Widget
buildFrame
(
{
bool
itemsWrap:
false
,
ViewportAnchor
scrollAnchor:
ViewportAnchor
.
start
,
List
<
int
>
pages:
defaultPages
})
{
final
PageableList
list
=
new
PageableList
(
children:
pages
.
map
(
buildPage
),
itemsWrap:
itemsWrap
,
scrollDirection:
Axis
.
horizontal
,
scrollAnchor:
scrollAnchor
,
onPageChanged:
(
int
page
)
{
currentPage
=
page
;
}
);
...
...
@@ -58,7 +62,6 @@ void main() {
test
(
'PageableList with itemsWrap: false'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
currentPage
=
null
;
itemsWrap
=
false
;
tester
.
pumpWidget
(
buildFrame
());
expect
(
currentPage
,
isNull
);
pageLeft
(
tester
);
...
...
@@ -86,11 +89,46 @@ void main() {
});
});
test
(
'PageableList with end scroll anchor'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
currentPage
=
5
;
tester
.
pumpWidget
(
buildFrame
(
scrollAnchor:
ViewportAnchor
.
end
));
pageRight
(
tester
);
expect
(
currentPage
,
equals
(
4
));
expect
(
tester
.
findText
(
'0'
),
isNull
);
expect
(
tester
.
findText
(
'1'
),
isNull
);
expect
(
tester
.
findText
(
'2'
),
isNull
);
expect
(
tester
.
findText
(
'3'
),
isNull
);
expect
(
tester
.
findText
(
'4'
),
isNotNull
);
expect
(
tester
.
findText
(
'5'
),
isNull
);
pageLeft
(
tester
);
expect
(
currentPage
,
equals
(
5
));
expect
(
tester
.
findText
(
'0'
),
isNull
);
expect
(
tester
.
findText
(
'1'
),
isNull
);
expect
(
tester
.
findText
(
'2'
),
isNull
);
expect
(
tester
.
findText
(
'3'
),
isNull
);
expect
(
tester
.
findText
(
'4'
),
isNull
);
expect
(
tester
.
findText
(
'5'
),
isNotNull
);
pageLeft
(
tester
);
expect
(
currentPage
,
equals
(
5
));
expect
(
tester
.
findText
(
'0'
),
isNull
);
expect
(
tester
.
findText
(
'1'
),
isNull
);
expect
(
tester
.
findText
(
'2'
),
isNull
);
expect
(
tester
.
findText
(
'3'
),
isNull
);
expect
(
tester
.
findText
(
'4'
),
isNull
);
expect
(
tester
.
findText
(
'5'
),
isNotNull
);
});
});
test
(
'PageableList with itemsWrap: true'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
currentPage
=
null
;
itemsWrap
=
true
;
tester
.
pumpWidget
(
buildFrame
());
tester
.
pumpWidget
(
buildFrame
(
itemsWrap:
true
));
expect
(
currentPage
,
isNull
);
pageLeft
(
tester
);
expect
(
currentPage
,
equals
(
1
));
...
...
@@ -101,11 +139,56 @@ void main() {
});
});
test
(
'PageableList with end and itemsWrap: true'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
currentPage
=
5
;
tester
.
pumpWidget
(
buildFrame
(
itemsWrap:
true
,
scrollAnchor:
ViewportAnchor
.
end
));
pageRight
(
tester
);
expect
(
currentPage
,
equals
(
4
));
expect
(
tester
.
findText
(
'0'
),
isNull
);
expect
(
tester
.
findText
(
'1'
),
isNull
);
expect
(
tester
.
findText
(
'2'
),
isNull
);
expect
(
tester
.
findText
(
'3'
),
isNull
);
expect
(
tester
.
findText
(
'4'
),
isNotNull
);
expect
(
tester
.
findText
(
'5'
),
isNull
);
pageLeft
(
tester
);
expect
(
currentPage
,
equals
(
5
));
expect
(
tester
.
findText
(
'0'
),
isNull
);
expect
(
tester
.
findText
(
'1'
),
isNull
);
expect
(
tester
.
findText
(
'2'
),
isNull
);
expect
(
tester
.
findText
(
'3'
),
isNull
);
expect
(
tester
.
findText
(
'4'
),
isNull
);
expect
(
tester
.
findText
(
'5'
),
isNotNull
);
pageLeft
(
tester
);
expect
(
currentPage
,
equals
(
0
));
expect
(
tester
.
findText
(
'0'
),
isNotNull
);
expect
(
tester
.
findText
(
'1'
),
isNull
);
expect
(
tester
.
findText
(
'2'
),
isNull
);
expect
(
tester
.
findText
(
'3'
),
isNull
);
expect
(
tester
.
findText
(
'4'
),
isNull
);
expect
(
tester
.
findText
(
'5'
),
isNull
);
pageLeft
(
tester
);
expect
(
currentPage
,
equals
(
1
));
expect
(
tester
.
findText
(
'0'
),
isNull
);
expect
(
tester
.
findText
(
'1'
),
isNotNull
);
expect
(
tester
.
findText
(
'2'
),
isNull
);
expect
(
tester
.
findText
(
'3'
),
isNull
);
expect
(
tester
.
findText
(
'4'
),
isNull
);
expect
(
tester
.
findText
(
'5'
),
isNull
);
});
});
test
(
'PageableList with two items'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
currentPage
=
null
;
itemsWrap
=
true
;
tester
.
pumpWidget
(
buildFrame
(
pages:
<
int
>[
0
,
1
]));
tester
.
pumpWidget
(
buildFrame
(
itemsWrap:
true
,
pages:
<
int
>[
0
,
1
]));
expect
(
currentPage
,
isNull
);
pageLeft
(
tester
);
expect
(
currentPage
,
equals
(
1
));
...
...
@@ -119,8 +202,7 @@ void main() {
test
(
'PageableList with one item'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
currentPage
=
null
;
itemsWrap
=
true
;
tester
.
pumpWidget
(
buildFrame
(
pages:
<
int
>[
0
]));
tester
.
pumpWidget
(
buildFrame
(
itemsWrap:
true
,
pages:
<
int
>[
0
]));
expect
(
currentPage
,
isNull
);
pageLeft
(
tester
);
expect
(
currentPage
,
equals
(
0
));
...
...
@@ -134,8 +216,7 @@ void main() {
test
(
'PageableList with no items'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
currentPage
=
null
;
itemsWrap
=
true
;
tester
.
pumpWidget
(
buildFrame
(
pages:
<
int
>[]));
tester
.
pumpWidget
(
buildFrame
(
itemsWrap:
true
,
pages:
<
int
>[]));
expect
(
currentPage
,
isNull
);
});
});
...
...
@@ -144,9 +225,8 @@ void main() {
testWidgets
((
WidgetTester
tester
)
{
tester
.
pumpWidget
(
new
Container
());
currentPage
=
null
;
itemsWrap
=
true
;
tester
.
pumpWidget
(
buildFrame
());
tester
.
pumpWidget
(
buildFrame
(
itemsWrap:
true
));
expect
(
currentPage
,
isNull
);
pageRight
(
tester
);
expect
(
currentPage
,
equals
(
5
));
...
...
@@ -156,7 +236,7 @@ void main() {
expect
(
box
.
size
.
height
,
equals
(
pageSize
.
height
));
pageSize
=
new
Size
(
pageSize
.
height
,
pageSize
.
width
);
tester
.
pumpWidget
(
buildFrame
());
tester
.
pumpWidget
(
buildFrame
(
itemsWrap:
true
));
expect
(
tester
.
findText
(
'0'
),
isNull
);
expect
(
tester
.
findText
(
'1'
),
isNull
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment