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
4d42f1a8
Unverified
Commit
4d42f1a8
authored
Aug 10, 2023
by
Ian Hickson
Committed by
GitHub
Aug 10, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
GridView sample code (#131900)
parent
60634c65
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
278 additions
and
16 deletions
+278
-16
grid_view.0.dart
examples/api/lib/widgets/scroll_view/grid_view.0.dart
+190
-0
grid_view.0_test.dart
examples/api/test/widgets/scroll_view/grid_view.0_test.dart
+32
-0
sliver_grid.dart
packages/flutter/lib/src/rendering/sliver_grid.dart
+33
-7
scroll_view.dart
packages/flutter/lib/src/widgets/scroll_view.dart
+23
-9
No files found.
examples/api/lib/widgets/scroll_view/grid_view.0.dart
0 → 100644
View file @
4d42f1a8
// Copyright 2014 The Flutter 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
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
void
main
(
)
=>
runApp
(
const
GridViewExampleApp
());
class
GridViewExampleApp
extends
StatelessWidget
{
const
GridViewExampleApp
({
super
.
key
});
@override
Widget
build
(
BuildContext
context
)
{
return
MaterialApp
(
home:
Padding
(
padding:
const
EdgeInsets
.
all
(
20.0
),
child:
Card
(
elevation:
8.0
,
child:
GridView
.
builder
(
padding:
const
EdgeInsets
.
all
(
12.0
),
gridDelegate:
CustomGridDelegate
(
dimension:
240.0
),
// Try uncommenting some of these properties to see the effect on the grid:
// itemCount: 20, // The default is that the number of grid tiles is infinite.
// scrollDirection: Axis.horizontal, // The default is vertical.
// reverse: true, // The default is false, going down (or left to right).
itemBuilder:
(
BuildContext
context
,
int
index
)
{
final
math
.
Random
random
=
math
.
Random
(
index
);
return
GridTile
(
header:
GridTileBar
(
title:
Text
(
'
$index
'
,
style:
const
TextStyle
(
color:
Colors
.
black
)),
),
child:
Container
(
margin:
const
EdgeInsets
.
all
(
12.0
),
decoration:
ShapeDecoration
(
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
12.0
),
),
gradient:
const
RadialGradient
(
colors:
<
Color
>[
Color
(
0x0F88EEFF
),
Color
(
0x2F0099BB
)
],
),
),
child:
FlutterLogo
(
style:
FlutterLogoStyle
.
values
[
random
.
nextInt
(
FlutterLogoStyle
.
values
.
length
)],
),
),
);
},
),
),
),
);
}
}
class
CustomGridDelegate
extends
SliverGridDelegate
{
CustomGridDelegate
({
required
this
.
dimension
});
// This is the desired height of each row (and width of each square).
// When there is not enough room, we shrink this to the width of the scroll view.
final
double
dimension
;
// The layout is two rows of squares, then one very wide cell, repeat.
@override
SliverGridLayout
getLayout
(
SliverConstraints
constraints
)
{
// Determine how many squares we can fit per row.
int
count
=
constraints
.
crossAxisExtent
~/
dimension
;
if
(
count
<
1
)
{
count
=
1
;
// Always fit at least one regardless.
}
final
double
squareDimension
=
constraints
.
crossAxisExtent
/
count
;
return
CustomGridLayout
(
crossAxisCount:
count
,
fullRowPeriod:
3
,
// Number of rows per block (one of which is the full row).
dimension:
squareDimension
,
);
}
@override
bool
shouldRelayout
(
CustomGridDelegate
oldDelegate
)
{
return
dimension
!=
oldDelegate
.
dimension
;
}
}
class
CustomGridLayout
extends
SliverGridLayout
{
const
CustomGridLayout
({
required
this
.
crossAxisCount
,
required
this
.
dimension
,
required
this
.
fullRowPeriod
,
})
:
assert
(
crossAxisCount
>
0
),
assert
(
fullRowPeriod
>
1
),
loopLength
=
crossAxisCount
*
(
fullRowPeriod
-
1
)
+
1
,
loopHeight
=
fullRowPeriod
*
dimension
;
final
int
crossAxisCount
;
final
double
dimension
;
final
int
fullRowPeriod
;
// Computed values.
final
int
loopLength
;
final
double
loopHeight
;
@override
double
computeMaxScrollOffset
(
int
childCount
)
{
// This returns the scroll offset of the end side of the childCount'th child.
// In the case of this example, this method is not used, since the grid is
// infinite. However, if one set an itemCount on the GridView above, this
// function would be used to determine how far to allow the user to scroll.
if
(
childCount
==
0
||
dimension
==
0
)
{
return
0
;
}
return
(
childCount
~/
loopLength
)
*
loopHeight
+
((
childCount
%
loopLength
)
~/
crossAxisCount
)
*
dimension
;
}
@override
SliverGridGeometry
getGeometryForChildIndex
(
int
index
)
{
// This returns the position of the index'th tile.
//
// The SliverGridGeometry object returned from this method has four
// properties. For a grid that scrolls down, as in this example, the four
// properties are equivalent to x,y,width,height. However, since the
// GridView is direction agnostic, the names used for SliverGridGeometry are
// also direction-agnostic.
//
// Try changing the scrollDirection and reverse properties on the GridView
// to see how this algorithm works in any direction (and why, therefore, the
// names are direction-agnostic).
final
int
loop
=
index
~/
loopLength
;
final
int
loopIndex
=
index
%
loopLength
;
if
(
loopIndex
==
loopLength
-
1
)
{
// Full width case.
return
SliverGridGeometry
(
scrollOffset:
(
loop
+
1
)
*
loopHeight
-
dimension
,
// "y"
crossAxisOffset:
0
,
// "x"
mainAxisExtent:
dimension
,
// "height"
crossAxisExtent:
crossAxisCount
*
dimension
,
// "width"
);
}
// Square case.
final
int
rowIndex
=
loopIndex
~/
crossAxisCount
;
final
int
columnIndex
=
loopIndex
%
crossAxisCount
;
return
SliverGridGeometry
(
scrollOffset:
(
loop
*
loopHeight
)
+
(
rowIndex
*
dimension
),
// "y"
crossAxisOffset:
columnIndex
*
dimension
,
// "x"
mainAxisExtent:
dimension
,
// "height"
crossAxisExtent:
dimension
,
// "width"
);
}
@override
int
getMinChildIndexForScrollOffset
(
double
scrollOffset
)
{
// This returns the first index that is visible for a given scrollOffset.
//
// The GridView only asks for the geometry of children that are visible
// between the scroll offset passed to getMinChildIndexForScrollOffset and
// the scroll offset passed to getMaxChildIndexForScrollOffset.
//
// It is the responsibility of the SliverGridLayout to ensure that
// getGeometryForChildIndex is consistent with getMinChildIndexForScrollOffset
// and getMaxChildIndexForScrollOffset.
//
// Not every child between the minimum child index and the maximum child
// index need be visible (some may have scroll offsets that are outside the
// view; this happens commonly when the grid view places tiles out of
// order). However, doing this means the grid view is less efficient, as it
// will do work for children that are not visible. It is preferred that the
// children are returned in the order that they are laid out.
final
int
rows
=
scrollOffset
~/
dimension
;
final
int
loops
=
rows
~/
fullRowPeriod
;
final
int
extra
=
rows
%
fullRowPeriod
;
return
loops
*
loopLength
+
extra
*
crossAxisCount
;
}
@override
int
getMaxChildIndexForScrollOffset
(
double
scrollOffset
)
{
// (See commentary above.)
final
int
rows
=
scrollOffset
~/
dimension
;
final
int
loops
=
rows
~/
fullRowPeriod
;
final
int
extra
=
rows
%
fullRowPeriod
;
final
int
count
=
loops
*
loopLength
+
extra
*
crossAxisCount
;
if
(
extra
==
fullRowPeriod
-
1
)
{
return
count
;
}
return
count
+
crossAxisCount
-
1
;
}
}
examples/api/test/widgets/scroll_view/grid_view.0_test.dart
0 → 100644
View file @
4d42f1a8
// Copyright 2014 The Flutter 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:flutter/rendering.dart'
;
import
'package:flutter_api_samples/widgets/scroll_view/grid_view.0.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
void
main
(
)
{
testWidgets
(
'
$CustomGridLayout
'
,
(
WidgetTester
tester
)
async
{
const
CustomGridLayout
layout
=
CustomGridLayout
(
crossAxisCount:
2
,
fullRowPeriod:
3
,
dimension:
100
,
);
final
List
<
double
>
scrollOffsets
=
List
<
double
>.
generate
(
10
,
(
int
i
)
=>
layout
.
computeMaxScrollOffset
(
i
));
expect
(
scrollOffsets
,
<
double
>[
0.0
,
0.0
,
100.0
,
100.0
,
200.0
,
300.0
,
300.0
,
400.0
,
400.0
,
500.0
]);
final
List
<
int
>
minOffsets
=
List
<
int
>.
generate
(
10
,
(
int
i
)
=>
layout
.
getMinChildIndexForScrollOffset
(
i
*
80.0
));
expect
(
minOffsets
,
<
int
>[
0
,
0
,
2
,
4
,
5
,
7
,
7
,
9
,
10
,
12
]);
final
List
<
int
>
maxOffsets
=
List
<
int
>.
generate
(
10
,
(
int
i
)
=>
layout
.
getMaxChildIndexForScrollOffset
(
i
*
80.0
));
expect
(
maxOffsets
,
<
double
>[
1
,
1
,
3
,
4
,
6
,
8
,
8
,
9
,
11
,
13
]);
final
List
<
SliverGridGeometry
>
offsets
=
List
<
SliverGridGeometry
>.
generate
(
20
,
(
int
i
)
=>
layout
.
getGeometryForChildIndex
(
i
));
offsets
.
reduce
((
SliverGridGeometry
a
,
SliverGridGeometry
b
)
{
if
(
a
.
scrollOffset
==
b
.
scrollOffset
)
{
expect
(
a
.
crossAxisOffset
,
lessThan
(
b
.
crossAxisOffset
));
}
else
{
expect
(
a
.
scrollOffset
,
lessThan
(
b
.
scrollOffset
));
}
return
b
;
});
});
}
packages/flutter/lib/src/rendering/sliver_grid.dart
View file @
4d42f1a8
...
...
@@ -13,6 +13,16 @@ import 'sliver_multi_box_adaptor.dart';
/// Describes the placement of a child in a [RenderSliverGrid].
///
/// This class is similar to [Rect], in that it gives a two-dimensional position
/// and a two-dimensional dimension, but is direction-agnostic.
///
/// {@tool dartpad}
/// This example shows how a custom [SliverGridLayout] uses [SliverGridGeometry]
/// to lay out the children.
///
/// ** See code in examples/api/lib/widgets/scroll_view/grid_view.0.dart **
/// {@end-tool}
///
/// See also:
///
/// * [SliverGridLayout], which represents the geometry of all the tiles in a
...
...
@@ -60,7 +70,7 @@ class SliverGridGeometry {
double
get
trailingScrollOffset
=>
scrollOffset
+
mainAxisExtent
;
/// Returns a tight [BoxConstraints] that forces the child to have the
/// required size.
/// required size
, given a [SliverConstraints]
.
BoxConstraints
getBoxConstraints
(
SliverConstraints
constraints
)
{
return
constraints
.
asBoxConstraints
(
minExtent:
mainAxisExtent
,
...
...
@@ -83,13 +93,22 @@ class SliverGridGeometry {
/// The size and position of all the tiles in a [RenderSliverGrid].
///
/// Rather that providing a grid with a [SliverGridLayout] directly, you instead
/// provide the grid a [SliverGridDelegate], which can compute a
/// [SliverGridLayout] given the current [SliverConstraints].
/// Rather that providing a grid with a [SliverGridLayout] directly, the grid is
/// provided a [SliverGridDelegate], which computes a [SliverGridLayout] given a
/// set of [SliverConstraints]. This allows the algorithm to dynamically respond
/// to changes in the environment (e.g. the user rotating the device).
///
/// The tiles can be placed arbitrarily, but it is more efficient to place tiles
/// in roughly in order by scroll offset because grids reify a contiguous
/// sequence of children.
/// roughly in order by scroll offset because grids reify a contiguous sequence
/// of children.
///
/// {@tool dartpad}
/// This example shows how to construct a custom [SliverGridLayout] to lay tiles
/// in a grid form with some cells stretched to fit the entire width of the
/// grid (sometimes called "hero tiles").
///
/// ** See code in examples/api/lib/widgets/scroll_view/grid_view.0.dart **
/// {@end-tool}
///
/// See also:
///
...
...
@@ -240,9 +259,16 @@ class SliverGridRegularTileLayout extends SliverGridLayout {
///
/// Given the current constraints on the grid, a [SliverGridDelegate] computes
/// the layout for the tiles in the grid. The tiles can be placed arbitrarily,
/// but it is more efficient to place tiles
in
roughly in order by scroll offset
/// but it is more efficient to place tiles roughly in order by scroll offset
/// because grids reify a contiguous sequence of children.
///
/// {@tool dartpad}
/// This example shows how a [SliverGridDelegate] returns a [SliverGridLayout]
/// configured based on the provided [SliverConstraints] in [getLayout].
///
/// ** See code in examples/api/lib/widgets/scroll_view/grid_view.0.dart **
/// {@end-tool}
///
/// See also:
///
/// * [SliverGridDelegateWithFixedCrossAxisCount], which creates a layout with
...
...
packages/flutter/lib/src/widgets/scroll_view.dart
View file @
4d42f1a8
...
...
@@ -1681,6 +1681,10 @@ class ListView extends BoxScrollView {
/// [SliverList] or [SliverAppBar], can be put in the [CustomScrollView.slivers]
/// list.
///
/// {@macro flutter.widgets.ScrollView.PageStorage}
///
/// ## Examples
///
/// {@tool snippet}
/// This example demonstrates how to create a [GridView] with two columns. The
/// children are spaced apart using the `crossAxisSpacing` and `mainAxisSpacing`
...
...
@@ -1786,6 +1790,25 @@ class ListView extends BoxScrollView {
/// ```
/// {@end-tool}
///
/// {@tool dartpad}
/// This example shows a custom implementation of selection in list and grid views.
/// Use the button in the top right (possibly hidden under the DEBUG banner) to toggle between
/// [ListView] and [GridView].
/// Long press any [ListTile] or [GridTile] to enable selection mode.
///
/// ** See code in examples/api/lib/widgets/scroll_view/list_view.0.dart **
/// {@end-tool}
///
/// {@tool dartpad}
/// This example shows a custom [SliverGridDelegate].
///
/// ** See code in examples/api/lib/widgets/scroll_view/grid_view.0.dart **
/// {@end-tool}
///
/// ## Troubleshooting
///
/// ### Padding
///
/// By default, [GridView] will automatically pad the limits of the
/// grid's scrollable to avoid partial obstructions indicated by
/// [MediaQuery]'s padding. To avoid this behavior, override with a
...
...
@@ -1817,15 +1840,6 @@ class ListView extends BoxScrollView {
/// ```
/// {@end-tool}
///
/// {@tool dartpad}
/// This example shows a custom implementation of [ListTile] selection in a [GridView] or [ListView].
/// Long press any ListTile to enable selection mode.
///
/// ** See code in examples/api/lib/widgets/scroll_view/list_view.0.dart **
/// {@end-tool}
///
/// {@macro flutter.widgets.ScrollView.PageStorage}
///
/// See also:
///
/// * [SingleChildScrollView], which is a scrollable widget that has a single
...
...
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