Flutter中滚动组件嵌套滚动组件

【转】原文地址。在 Flutter 中,如果想在 scrollview 里面嵌套另一个 listview 的话,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Scaffold(
appBar: AppBar(
title: Text("ListView"),
),
body: Container(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
HeaderWidget("Header 1"),
HeaderWidget("Header 2"),
HeaderWidget("Header 3"),
HeaderWidget("Header 4"),
ListView(
children: <Widget>[
BodyWidget(Colors.blue),
BodyWidget(Colors.red),
BodyWidget(Colors.green),
],
),
],
),
),
),
);

会报错:

1
2
3
4
5
6
7
8
9
10
══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY╞══════════════════════
I/flutter ( 3423): The following assertion was thrown during performResize():
I/flutter ( 3423): Vertical viewport was given unbounded height.
I/flutter ( 3423): Viewports expand in the scrolling direction to fill their container.In this case, a vertical
I/flutter ( 3423): viewport was given an unlimited amount of vertical space in which to expand. This situation
I/flutter ( 3423): typically happens when a scrollable widget is nested inside another scrollable widget.
I/flutter ( 3423): If this widget is always nested in a scrollable widget there is no need to use a viewport because
I/flutter ( 3423): there will always be enough vertical space for the children. In this case, consider using a Column
I/flutter ( 3423): instead. Otherwise, consider using the "shrinkWrap" property (or a ShrinkWrappingViewport) to size
I/flutter ( 3423): the height of the viewport to the sum of the heights of its children.

意思是说不能把一个无限长度的组件,例如 ListView 和 GridView 直接放到一个 Scrollable 组件里面。那如果要达到这种效果,应该怎么办呢?答案就是 Slivers,示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Scaffold(
appBar: AppBar(
title: Text("ListView"),
),
body: Container(
child: CustomScrollView(
slivers: <Widget>[
SliverList(
delegate: SliverChildListDelegate(
[
HeaderWidget("Header 1"),
HeaderWidget("Header 2"),
HeaderWidget("Header 3"),
HeaderWidget("Header 4"),
],
),
),
SliverList(
delegate: SliverChildListDelegate(
[
BodyWidget(Colors.blue),
BodyWidget(Colors.red),
BodyWidget(Colors.green),
BodyWidget(Colors.orange),
BodyWidget(Colors.blue),
BodyWidget(Colors.red),
],
),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
delegate: SliverChildListDelegate(
[
BodyWidget(Colors.blue),
BodyWidget(Colors.green),
BodyWidget(Colors.yellow),
BodyWidget(Colors.orange),
BodyWidget(Colors.blue),
BodyWidget(Colors.red),
],
),
),
],
),
),
);

上面的代码主要做了如下的工作:

  1. 把 SingleChildScrollView 换成 CustomScrollView.
  2. 把 Column 或者 ListView 换成 SliverList
  3. 把 GridView 换成 SliverGrid

如此以来,即可实现在滚动组件中嵌套滚动组件了。最终效果如下:

flutter-slivers