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
888dc770
Commit
888dc770
authored
Jan 04, 2016
by
Adam Barth
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1063 from abarth/scrollable_grid
Add support for scrollable grids
parents
35b18c3d
6106fa9d
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
348 additions
and
23 deletions
+348
-23
media_query.dart
examples/widgets/media_query.dart
+3
-7
block.dart
packages/flutter/lib/src/rendering/block.dart
+3
-1
grid.dart
packages/flutter/lib/src/rendering/grid.dart
+117
-15
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+2
-0
homogeneous_viewport.dart
packages/flutter/lib/src/widgets/homogeneous_viewport.dart
+1
-0
scrollable_grid.dart
packages/flutter/lib/src/widgets/scrollable_grid.dart
+221
-0
widgets.dart
packages/flutter/lib/widgets.dart
+1
-0
No files found.
examples/widgets/media_query.dart
View file @
888dc770
...
...
@@ -76,13 +76,9 @@ class MediaQueryExample extends StatelessComponent {
items
.
map
((
AdaptiveItem
item
)
=>
item
.
toListItem
()).
toList
()
);
}
else
{
return
new
Block
(
<
Widget
>[
new
MaxTileWidthGrid
(
items
.
map
((
AdaptiveItem
item
)
=>
item
.
toCard
()).
toList
(),
maxTileWidth:
_maxTileWidth
)
]
return
new
ScrollableGrid
(
children:
items
.
map
((
AdaptiveItem
item
)
=>
item
.
toCard
()).
toList
(),
delegate:
new
MaxTileWidthGridDelegate
(
maxTileWidth:
_maxTileWidth
)
);
}
}
...
...
packages/flutter/lib/src/rendering/block.dart
View file @
888dc770
...
...
@@ -261,7 +261,7 @@ class RenderBlockViewport extends RenderBlockBase {
bool
_inCallback
=
false
;
bool
get
hasLayer
=>
true
;
/// Called during [layout] to determine the blocks children.
/// Called during [layout] to determine the block
'
s children.
///
/// Typically the callback will mutate the child list appropriately, for
/// example so the child list contains only visible children.
...
...
@@ -396,7 +396,9 @@ class RenderBlockViewport extends RenderBlockBase {
// scroll the RenderBlockViewport, it would shift in its parent if
// the parent was baseline-aligned, which makes no sense.
// TODO(abarth): debugDoesLayoutWithCallback appears to be unreferenced.
bool
get
debugDoesLayoutWithCallback
=>
true
;
void
performLayout
()
{
if
(
_callback
!=
null
)
{
try
{
...
...
packages/flutter/lib/src/rendering/grid.dart
View file @
888dc770
...
...
@@ -2,9 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:typed_data'
;
import
'box.dart'
;
import
'object.dart'
;
import
'package:vector_math/vector_math_64.dart'
;
bool
_debugIsMonotonic
(
List
<
double
>
offsets
)
{
bool
result
=
true
;
assert
(()
{
...
...
@@ -23,7 +27,7 @@ bool _debugIsMonotonic(List<double> offsets) {
List
<
double
>
_generateRegularOffsets
(
int
count
,
double
size
)
{
int
length
=
count
+
1
;
List
<
double
>
result
=
new
List
<
double
>
(
length
);
List
<
double
>
result
=
new
Float64List
(
length
);
for
(
int
i
=
0
;
i
<
length
;
++
i
)
result
[
i
]
=
i
*
size
;
return
result
;
...
...
@@ -87,6 +91,12 @@ class GridSpecification {
/// The size of the grid.
Size
get
gridSize
=>
new
Size
(
columnOffsets
.
last
+
padding
.
horizontal
,
rowOffsets
.
last
+
padding
.
vertical
);
/// The number of columns in this grid.
int
get
columnCount
=>
columnOffsets
.
length
-
1
;
/// The number of rows in this grid.
int
get
rowCount
=>
rowOffsets
.
length
-
1
;
}
/// Where to place a child within a grid.
...
...
@@ -308,8 +318,16 @@ class RenderGrid extends RenderBox with ContainerRenderObjectMixin<RenderBox, Gr
RenderBoxContainerDefaultsMixin
<
RenderBox
,
GridParentData
>
{
RenderGrid
({
List
<
RenderBox
>
children
,
GridDelegate
delegate
})
:
_delegate
=
delegate
{
GridDelegate
delegate
,
int
virtualChildBase:
0
,
int
virtualChildCount
,
Offset
paintOffset:
Offset
.
zero
,
LayoutCallback
callback
})
:
_delegate
=
delegate
,
_virtualChildBase
=
virtualChildBase
,
_virtualChildCount
=
virtualChildCount
,
_paintOffset
=
paintOffset
,
_callback
=
callback
{
assert
(
delegate
!=
null
);
addAll
(
children
);
}
...
...
@@ -321,11 +339,70 @@ class RenderGrid extends RenderBox with ContainerRenderObjectMixin<RenderBox, Gr
assert
(
newDelegate
!=
null
);
if
(
_delegate
==
newDelegate
)
return
;
if
(
newDelegate
.
runtimeType
!=
_delegate
.
runtimeType
||
newDelegate
.
shouldRelayout
(
_delegate
))
if
(
newDelegate
.
runtimeType
!=
_delegate
.
runtimeType
||
newDelegate
.
shouldRelayout
(
_delegate
))
{
_specification
=
null
;
markNeedsLayout
();
}
_delegate
=
newDelegate
;
}
/// The virtual index of the first child.
///
/// When asking the delegate for the position of each child, the grid will add
/// the virtual child i to the indices of its children.
int
get
virtualChildBase
=>
_virtualChildBase
;
int
_virtualChildBase
;
void
set
virtualChildBase
(
int
value
)
{
assert
(
value
!=
null
);
if
(
_virtualChildBase
==
value
)
return
;
_virtualChildBase
=
value
;
markNeedsLayout
();
}
/// The total number of virtual children in the grid.
///
/// When asking the delegate for the grid specification, the grid will use
/// this number of children, which can be larger than the actual number of
/// children of this render object.
///
/// If the this value is null, the grid will use the actual child count of
/// this render object.
int
get
virtualChildCount
=>
_virtualChildCount
??
childCount
;
int
_virtualChildCount
;
void
set
virtualChildCount
(
int
value
)
{
if
(
_virtualChildCount
==
value
)
return
;
_virtualChildCount
=
value
;
markNeedsLayout
();
}
/// The offset at which to paint the first tile.
///
/// Note: you can modify this property from within [callback], if necessary.
Offset
get
paintOffset
=>
_paintOffset
;
Offset
_paintOffset
;
void
set
paintOffset
(
Offset
value
)
{
assert
(
value
!=
null
);
if
(
value
==
_paintOffset
)
return
;
_paintOffset
=
value
;
markNeedsPaint
();
}
/// Called during [layout] to determine the grid's children.
///
/// Typically the callback will mutate the child list appropriately, for
/// example so the child list contains only visible children.
LayoutCallback
get
callback
=>
_callback
;
LayoutCallback
_callback
;
void
set
callback
(
LayoutCallback
value
)
{
if
(
value
==
_callback
)
return
;
_callback
=
value
;
markNeedsLayout
();
}
void
setupParentData
(
RenderBox
child
)
{
if
(
child
.
parentData
is
!
GridParentData
)
child
.
parentData
=
new
GridParentData
();
...
...
@@ -333,46 +410,63 @@ class RenderGrid extends RenderBox with ContainerRenderObjectMixin<RenderBox, Gr
double
getMinIntrinsicWidth
(
BoxConstraints
constraints
)
{
assert
(
constraints
.
isNormalized
);
return
_delegate
.
getMinIntrinsicWidth
(
constraints
,
c
hildCount
);
return
_delegate
.
getMinIntrinsicWidth
(
constraints
,
virtualC
hildCount
);
}
double
getMaxIntrinsicWidth
(
BoxConstraints
constraints
)
{
assert
(
constraints
.
isNormalized
);
return
_delegate
.
getMaxIntrinsicWidth
(
constraints
,
c
hildCount
);
return
_delegate
.
getMaxIntrinsicWidth
(
constraints
,
virtualC
hildCount
);
}
double
getMinIntrinsicHeight
(
BoxConstraints
constraints
)
{
assert
(
constraints
.
isNormalized
);
return
_delegate
.
getMinIntrinsicHeight
(
constraints
,
c
hildCount
);
return
_delegate
.
getMinIntrinsicHeight
(
constraints
,
virtualC
hildCount
);
}
double
getMaxIntrinsicHeight
(
BoxConstraints
constraints
)
{
assert
(
constraints
.
isNormalized
);
return
_delegate
.
getMaxIntrinsicHeight
(
constraints
,
c
hildCount
);
return
_delegate
.
getMaxIntrinsicHeight
(
constraints
,
virtualC
hildCount
);
}
double
computeDistanceToActualBaseline
(
TextBaseline
baseline
)
{
return
defaultComputeDistanceToHighestActualBaseline
(
baseline
);
}
GridSpecification
get
specification
=>
_specification
;
GridSpecification
_specification
;
int
_specificationChildCount
;
BoxConstraints
_specificationConstraints
;
void
_updateGridSpecification
()
{
if
(
_specification
==
null
||
_specificationChildCount
!=
virtualChildCount
||
_specificationConstraints
!=
constraints
)
{
_specification
=
delegate
.
getGridSpecification
(
constraints
,
virtualChildCount
);
_specificationChildCount
=
virtualChildCount
;
_specificationConstraints
=
constraints
;
}
}
bool
_hasVisualOverflow
=
false
;
void
performLayout
()
{
_
specification
=
delegate
.
getGridSpecification
(
constraints
,
childCount
);
_
updateGridSpecification
(
);
Size
gridSize
=
_specification
.
gridSize
;
size
=
constraints
.
constrain
(
gridSize
);
if
(
gridSize
.
width
>
size
.
width
||
gridSize
.
height
>
size
.
height
)
_hasVisualOverflow
=
true
;
if
(
_callback
!=
null
)
invokeLayoutCallback
(
_callback
);
double
gridTopPadding
=
_specification
.
padding
.
top
;
double
gridLeftPadding
=
_specification
.
padding
.
left
;
int
index
=
0
;
int
childIndex
=
virtualChildBase
;
RenderBox
child
=
firstChild
;
while
(
child
!=
null
)
{
final
GridParentData
childParentData
=
child
.
parentData
;
GridChildPlacement
placement
=
delegate
.
getChildPlacement
(
_specification
,
i
ndex
,
childParentData
.
placementData
);
GridChildPlacement
placement
=
delegate
.
getChildPlacement
(
_specification
,
childI
ndex
,
childParentData
.
placementData
);
assert
(
placement
.
column
>=
0
);
assert
(
placement
.
row
>=
0
);
assert
(
placement
.
column
+
placement
.
columnSpan
<
_specification
.
columnOffsets
.
length
);
...
...
@@ -398,21 +492,29 @@ class RenderGrid extends RenderBox with ContainerRenderObjectMixin<RenderBox, Gr
tileTop
+
placement
.
padding
.
top
);
++
i
ndex
;
++
childI
ndex
;
assert
(
child
.
parentData
==
childParentData
);
child
=
childParentData
.
nextSibling
;
}
}
void
applyPaintTransform
(
RenderBox
child
,
Matrix4
transform
)
{
super
.
applyPaintTransform
(
child
,
transform
.
translate
(
paintOffset
));
}
bool
hitTestChildren
(
HitTestResult
result
,
{
Point
position
})
{
return
defaultHitTestChildren
(
result
,
position:
position
);
return
defaultHitTestChildren
(
result
,
position:
position
+
-
paintOffset
);
}
void
_paintContents
(
PaintingContext
context
,
Offset
offset
)
{
defaultPaint
(
context
,
offset
+
paintOffset
);
}
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
if
(
_hasVisualOverflow
)
context
.
pushClipRect
(
needsCompositing
,
offset
,
Point
.
origin
&
size
,
defaultPaint
);
context
.
pushClipRect
(
needsCompositing
,
offset
,
Point
.
origin
&
size
,
_paintContents
);
else
defaultPaint
(
context
,
offset
);
_paintContents
(
context
,
offset
);
}
}
packages/flutter/lib/src/widgets/basic.dart
View file @
888dc770
...
...
@@ -29,6 +29,7 @@ export 'package:flutter/rendering.dart' show
FlexAlignItems
,
FlexDirection
,
FlexJustifyContent
,
FixedColumnCountGridDelegate
,
FontStyle
,
FontWeight
,
FractionalOffset
,
...
...
@@ -40,6 +41,7 @@ export 'package:flutter/rendering.dart' show
InputEvent
,
LinearGradient
,
Matrix4
,
MaxTileWidthGridDelegate
,
Offset
,
OneChildLayoutDelegate
,
Paint
,
...
...
packages/flutter/lib/src/widgets/homogeneous_viewport.dart
View file @
888dc770
...
...
@@ -79,6 +79,7 @@ abstract class _ViewportBaseElement<T extends _ViewportBase> extends RenderObjec
void
update
(
T
newWidget
)
{
bool
needLayout
=
newWidget
.
isLayoutDifferentThan
(
widget
);
super
.
update
(
newWidget
);
// TODO(abarth): Don't we need to update overlayPainter here?
if
(
needLayout
)
renderObject
.
markNeedsLayout
();
else
...
...
packages/flutter/lib/src/widgets/scrollable_grid.dart
0 → 100644
View file @
888dc770
// 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
'dart:math'
as
math
;
import
'basic.dart'
;
import
'framework.dart'
;
import
'scrollable.dart'
;
import
'package:flutter/animation.dart'
;
import
'package:flutter/rendering.dart'
;
/// A vertically scrollable grid.
///
/// Requires that delegate places its children in row-major order.
class
ScrollableGrid
extends
Scrollable
{
ScrollableGrid
({
Key
key
,
double
initialScrollOffset
,
ScrollListener
onScroll
,
SnapOffsetCallback
snapOffsetCallback
,
double
snapAlignmentOffset:
0.0
,
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:
ScrollDirection
.
vertical
,
onScroll:
onScroll
,
snapOffsetCallback:
snapOffsetCallback
,
snapAlignmentOffset:
snapAlignmentOffset
);
final
GridDelegate
delegate
;
final
List
<
Widget
>
children
;
ScrollableState
createState
()
=>
new
_ScrollableGrid
();
}
class
_ScrollableGrid
extends
ScrollableState
<
ScrollableGrid
>
{
ScrollBehavior
createScrollBehavior
()
=>
new
OverscrollWhenScrollableBehavior
();
ExtentScrollBehavior
get
scrollBehavior
=>
super
.
scrollBehavior
;
void
_handleExtentsChanged
(
double
contentExtent
,
double
containerExtent
)
{
setState
(()
{
scrollTo
(
scrollBehavior
.
updateExtents
(
contentExtent:
contentExtent
,
containerExtent:
containerExtent
,
scrollOffset:
scrollOffset
));
});
}
Widget
buildContent
(
BuildContext
context
)
{
return
new
GridViewport
(
startOffset:
scrollOffset
,
delegate:
config
.
delegate
,
onExtentsChanged:
_handleExtentsChanged
,
children:
config
.
children
);
}
}
typedef
void
ExtentsChangedCallback
(
double
contentExtent
,
double
containerExtent
);
class
GridViewport
extends
RenderObjectWidget
{
GridViewport
({
Key
key
,
this
.
startOffset
,
this
.
delegate
,
this
.
onExtentsChanged
,
this
.
children
});
final
double
startOffset
;
final
GridDelegate
delegate
;
final
ExtentsChangedCallback
onExtentsChanged
;
final
List
<
Widget
>
children
;
RenderGrid
createRenderObject
()
=>
new
RenderGrid
(
delegate:
delegate
);
_GridViewportElement
createElement
()
=>
new
_GridViewportElement
(
this
);
}
// TODO(abarth): This function should go somewhere more general.
int
_lowerBound
(
List
sortedList
,
var
value
,
{
int
begin:
0
})
{
int
current
=
begin
;
int
count
=
sortedList
.
length
-
current
;
while
(
count
>
0
)
{
int
step
=
count
>>
1
;
int
test
=
current
+
step
;
if
(
sortedList
[
test
]
<
value
)
{
current
=
test
+
1
;
count
-=
step
+
1
;
}
else
{
count
=
step
;
}
}
return
current
;
}
class
_GridViewportElement
extends
RenderObjectElement
<
GridViewport
>
{
_GridViewportElement
(
GridViewport
widget
)
:
super
(
widget
);
double
_contentExtent
;
double
_containerExtent
;
int
_materializedChildBase
;
int
_materializedChildCount
;
List
<
Element
>
_materializedChildren
=
const
<
Element
>[];
GridSpecification
_specification
;
double
_repaintOffsetBase
;
double
_repaintOffsetLimit
;
RenderGrid
get
renderObject
=>
super
.
renderObject
;
void
visitChildren
(
ElementVisitor
visitor
)
{
if
(
_materializedChildren
==
null
)
return
;
for
(
Element
child
in
_materializedChildren
)
visitor
(
child
);
}
void
mount
(
Element
parent
,
dynamic
newSlot
)
{
super
.
mount
(
parent
,
newSlot
);
renderObject
.
callback
=
layout
;
_updateRenderObject
();
}
void
unmount
()
{
renderObject
.
callback
=
null
;
super
.
unmount
();
}
void
update
(
GridViewport
newWidget
)
{
super
.
update
(
newWidget
);
_updateRenderObject
();
if
(!
renderObject
.
needsLayout
)
_materializeChildren
();
}
void
_updatePaintOffset
()
{
renderObject
.
paintOffset
=
new
Offset
(
0.0
,
-(
widget
.
startOffset
-
_repaintOffsetBase
));
}
void
_updateRenderObject
()
{
renderObject
.
delegate
=
widget
.
delegate
;
renderObject
.
virtualChildCount
=
widget
.
children
.
length
;
if
(
_specification
!=
null
)
{
_updatePaintOffset
();
// If we don't already need layout, we need to request a layout if the
// viewport has shifted to expose a new row.
if
(!
renderObject
.
needsLayout
)
{
if
(
_repaintOffsetBase
!=
null
&&
widget
.
startOffset
<
_repaintOffsetBase
)
renderObject
.
markNeedsLayout
();
else
if
(
_repaintOffsetLimit
!=
null
&&
widget
.
startOffset
+
_containerExtent
>
_repaintOffsetLimit
)
renderObject
.
markNeedsLayout
();
}
}
}
void
_materializeChildren
()
{
assert
(
_materializedChildBase
!=
null
);
assert
(
_materializedChildCount
!=
null
);
List
<
Widget
>
newWidgets
=
new
List
<
Widget
>(
_materializedChildCount
);
for
(
int
i
=
0
;
i
<
_materializedChildCount
;
++
i
)
{
int
childIndex
=
_materializedChildBase
+
i
;
Widget
child
=
widget
.
children
[
childIndex
];
Key
key
=
new
ValueKey
(
child
.
key
??
childIndex
);
newWidgets
[
i
]
=
new
RepaintBoundary
(
key:
key
,
child:
child
);
}
_materializedChildren
=
updateChildren
(
_materializedChildren
,
newWidgets
);
}
void
layout
(
BoxConstraints
constraints
)
{
_specification
=
renderObject
.
specification
;
double
contentExtent
=
_specification
.
gridSize
.
height
;
double
containerExtent
=
renderObject
.
size
.
height
;
int
materializedRowBase
=
math
.
max
(
0
,
_lowerBound
(
_specification
.
rowOffsets
,
widget
.
startOffset
)
-
1
);
int
materializedRowLimit
=
math
.
min
(
_specification
.
rowCount
,
_lowerBound
(
_specification
.
rowOffsets
,
widget
.
startOffset
+
containerExtent
));
_materializedChildBase
=
materializedRowBase
*
_specification
.
columnCount
;
_materializedChildCount
=
math
.
min
(
widget
.
children
.
length
,
materializedRowLimit
*
_specification
.
columnCount
)
-
_materializedChildBase
;
_repaintOffsetBase
=
_specification
.
rowOffsets
[
materializedRowBase
];
_repaintOffsetLimit
=
_specification
.
rowOffsets
[
materializedRowLimit
];
_updatePaintOffset
();
BuildableElement
.
lockState
(
_materializeChildren
);
if
(
contentExtent
!=
_contentExtent
||
containerExtent
!=
_containerExtent
)
{
_contentExtent
=
contentExtent
;
_containerExtent
=
containerExtent
;
widget
.
onExtentsChanged
(
_contentExtent
,
_containerExtent
);
}
}
void
insertChildRenderObject
(
RenderObject
child
,
Element
slot
)
{
RenderObject
nextSibling
=
slot
?.
renderObject
;
renderObject
.
add
(
child
,
before:
nextSibling
);
}
void
moveChildRenderObject
(
RenderObject
child
,
Element
slot
)
{
assert
(
child
.
parent
==
renderObject
);
RenderObject
nextSibling
=
slot
?.
renderObject
;
renderObject
.
move
(
child
,
before:
nextSibling
);
}
void
removeChildRenderObject
(
RenderObject
child
)
{
assert
(
child
.
parent
==
renderObject
);
renderObject
.
remove
(
child
);
}
}
packages/flutter/lib/widgets.dart
View file @
888dc770
...
...
@@ -32,6 +32,7 @@ export 'src/widgets/pageable_list.dart';
export
'src/widgets/placeholder.dart'
;
export
'src/widgets/routes.dart'
;
export
'src/widgets/scrollable.dart'
;
export
'src/widgets/scrollable_grid.dart'
;
export
'src/widgets/statistics_overlay.dart'
;
export
'src/widgets/status_transitions.dart'
;
export
'src/widgets/title.dart'
;
...
...
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