Skip to content

Commit 3cb68d8

Browse files
author
yangshangzhi
committed
feat: 增加nestscrollview’
1 parent e5d49e9 commit 3cb68d8

File tree

9 files changed

+230
-10
lines changed

9 files changed

+230
-10
lines changed

docs/widget/scrollview/customscrollview/index.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,14 @@ CustomScrollView({
2626
- CustomScrollView: 实现随滚动条,appbar向上移动效果
2727
- SingleChildScrollView:参考SingleChildScrollView
2828

29-
### CustomScrollView
30-
> CustomScrollView:结合slivers使用,常用小组件为SliverAppBar, SliverGrid,SliverFixedExtentList
29+
> Sliver:视图内的小片,细片。通常带有特定滚动效果的滚动块。常用小组件
30+
- SliverAppBar
31+
- SliverGrid
32+
- SliverFixedExtentList
33+
- ...
34+
3135
> SliverAppBar: 滚动标题头小组件
32-
```dart
36+
```
3337
SliverAppBar({
3438
Key key,
3539
this.leading,
@@ -56,4 +60,7 @@ CustomScrollView({
5660
```
5761
- pinned: 默认为false, 非滚动至顶部时,标题头始终处于隐藏,当true时,标题头始终显示,但不会显示flexibleSpace内容
5862
- floating: 默认为false,当为true时,下拉会显示appbar,但不会自动展开flexibleSpace的内容
59-
- snap: 默认为false,当floating为true, 当前才能为true,向下拉时,会自动显示flexibleSpace的内容
63+
- snap: 默认为false,当floating为true, 当前才能为true,向下拉时,会自动显示flexibleSpace的内容
64+
- expandedHeight: 展开的最大高度
65+
- forceElevated:bool appbar下方阴影
66+
- flexibleSpace: expandedHeight展开后的内容
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
## **NestedScrollView**
2+
> 该滚动组件内部可嵌套滚动组件, 通常SliverAppBar+TabBar作为头部headerSliverBuilder,TabBarView作为主体body结合使用。
3+
4+
### 构造函数
5+
```
6+
NestedScrollView({
7+
Key key,
8+
this.controller,
9+
this.scrollDirection = Axis.vertical,
10+
this.reverse = false,
11+
this.physics,
12+
@required this.headerSliverBuilder,
13+
@required this.body,
14+
this.dragStartBehavior = DragStartBehavior.down,
15+
})
16+
```
17+
18+
### 属性介绍
19+
- headerSliverBuilder: 控制appbar相关内容,接收数组组件。return [SliverOverlapAbsorber()]
20+
- body: 组件滚动部分
21+
22+
### 相关属性
23+
> SliverOverlapAbsorber 构造函数
24+
```
25+
SliverOverlapAbsorber({
26+
Key key,
27+
@required this.handle,
28+
Widget child,
29+
})
30+
```
31+
32+
> SliverOverlapInjector 构造函数
33+
```
34+
SliverOverlapInjector({
35+
Key key,
36+
@required this.handle,
37+
Widget child,
38+
})
39+
```
40+
- SliverOverlapAbsorber: 该组件将一些带有重叠行为的组件,把重叠部分通过SliverOverlapInjector进行占位,使得整个页面衔接。(相关重叠可以参考CustomScrollView)
41+
- SliverOverlapInjector: 与SliverOverlapAbsorber对应,填充交叠部分。
42+
- handle: SliverOverlapAbsorberHandle, 通过NestedScrollView.sliverOverlapAbsorberHandleFor(context)回调,返回父级NestedScrollView,
43+
- 更多查看代码注释

lib/page/component/index.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ class _IndexState extends State<Index> {
9999
physics: BouncingScrollPhysics(),
100100
// padding: EdgeInsets.all(10),
101101
child: ExpansionPanelList(
102-
animationDuration: Duration(milliseconds: 800),
102+
animationDuration: Duration(milliseconds: 500),
103103
children: List.generate(
104104
_mapList.length,
105105
(_index) {

lib/widget/scrollview/customscrollview/demo_custom_scrollview.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ class _IndexState extends State<Index> {
2020
return CustomScrollView(
2121
slivers: [
2222
SliverAppBar(
23+
forceElevated: false, // appbar下方阴影
2324
snap: false,
2425
// 当floating为true,当前才能为true,向下拉时,会自动显示flexibleSpace的内容
2526
pinned: false,
2627
// 当pinned为true时,一直显示标题,但不显示flexibleSpace的内容
2728
expandedHeight: 250.0,
28-
title: Text('this title'),
29+
title: Text('ScrollView'),
2930
flexibleSpace: FlexibleSpaceBar(
3031
title: Text(
3132
'这里的标题会随着滚动向上移),',

lib/widget/scrollview/gridview/demo_extent.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class Index extends StatelessWidget {
2323
width: 0.1,
2424
)
2525
),
26-
child: Image.network('https://dianhu-1253537286.cos.eu-moscow.myqcloud.com/efoxfile/Moschat/ojbk.png'),
26+
child: Image.network('https://static.moschat.com/efoxfile/Moschat/ojbk.png'),
2727
);
2828
},
2929
),

lib/widget/scrollview/index.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'customscrollview/index.dart' as customscrollview;
66
import 'singlechildscrollview/index.dart' as singlechildscrollview;
77
import 'scrollbar/index.dart' as scrollbar;
88
import 'scrollcontroller/index.dart' as scrollcontroller;
9+
import 'nestedscrollview/index.dart' as nestedscrollview;
910

1011
const nameSpaces = '/scrollview_';
1112

@@ -42,9 +43,14 @@ List widgets = [
4243
),
4344
ItemInfo(
4445
widget: scrollcontroller.Index(),
45-
code: 57945, // vertical_align_center
46+
code: 57539, // import_export
4647
title: scrollcontroller.Index.title,
4748
),
49+
ItemInfo(
50+
widget: nestedscrollview.Index(),
51+
code: 57945, // vertical_align_center
52+
title: nestedscrollview.Index.title,
53+
),
4854
];
4955

5056
List widgetMap = [
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import 'package:flutter/material.dart';
2+
3+
class Index extends StatefulWidget {
4+
@override
5+
State<StatefulWidget> createState() => _IndexState();
6+
}
7+
8+
class _IndexState extends State<Index> {
9+
List<String> _tabs;
10+
11+
@override
12+
void initState() {
13+
super.initState();
14+
_tabs = ['tab_1', 'tab_2'];
15+
}
16+
17+
@override
18+
Widget build(BuildContext context) {
19+
return DefaultTabController(
20+
length: _tabs.length, // This is the number of tabs.
21+
child: NestedScrollView(
22+
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
23+
// These are the slivers that show up in the "outer" scroll view.
24+
return <Widget>[
25+
SliverOverlapAbsorber(
26+
// This widget takes the overlapping behavior of the SliverAppBar,
27+
// and redirects it to the SliverOverlapInjector below. If it is
28+
// missing, then it is possible for the nested "inner" scroll view
29+
// below to end up under the SliverAppBar even when the inner
30+
// scroll view thinks it has not been scrolled.
31+
// This is not necessary if the "headerSliverBuilder" only builds
32+
// widgets that do not overlap the next sliver.
33+
// 交叠减震器,当组件滚动造成交叠、覆盖时,可以增加SliverOverlapAbsorber
34+
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
35+
child: SliverAppBar(
36+
title: const Text(
37+
'NestedScrollView'), // This is the title in the app bar.
38+
pinned: true, // 固定顶部appbar
39+
expandedHeight: 200.0, // 展开显示面板的最大高度
40+
// The "forceElevated" property causes the SliverAppBar to show
41+
// a shadow. The "innerBoxIsScrolled" parameter is true when the
42+
// inner scroll view is scrolled beyond its "zero" point, i.e.
43+
// when it appears to be scrolled below the SliverAppBar.
44+
// Without this, there are cases where the shadow would appear
45+
// or not appear inappropriately, because the SliverAppBar is
46+
// not actually aware of the precise position of the inner
47+
// scroll views.
48+
forceElevated: innerBoxIsScrolled, // appbar底部阴影
49+
bottom: TabBar(
50+
// These are the widgets to put in each tab in the tab bar.
51+
tabs: _tabs.map((String name) => Tab(text: name)).toList(),
52+
),
53+
// appbar导航左侧按钮
54+
leading: Container(
55+
child: Icon(Icons.access_alarm),
56+
),
57+
flexibleSpace: FlexibleSpaceBar(
58+
background: Image.network(
59+
'https://static.moschat.com/efoxfile/Moschat/ojbk.png',
60+
filterQuality: FilterQuality.high,
61+
fit: BoxFit.none,
62+
),
63+
),
64+
),
65+
),
66+
];
67+
},
68+
body: TabBarView(
69+
// These are the contents of the tab views, below the tabs.
70+
children: _tabs.map((String name) {
71+
return SafeArea(
72+
top: true,
73+
bottom: true,
74+
child: Builder(
75+
// This Builder is needed to provide a BuildContext that is "inside"
76+
// the NestedScrollView, so that sliverOverlapAbsorberHandleFor() can
77+
// find the NestedScrollView.
78+
builder: (BuildContext context) {
79+
return CustomScrollView(
80+
// The "controller" and "primary" members should be left
81+
// unset, so that the NestedScrollView can control this
82+
// inner scroll view.
83+
// If the "controller" property is set, then this scroll
84+
// view will not be associated with the NestedScrollView.
85+
// The PageStorageKey should be unique to this ScrollView;
86+
// it allows the list to remember its scroll position when
87+
// the tab view is not on the screen.
88+
// controller跟primary属性不需要在此设置,否则会独立与NestedScrollView的控制。
89+
key: PageStorageKey<String>(name),
90+
slivers: <Widget>[
91+
// SliverOverlapInjector与SliverOverlapAbsorber是相对成立的,
92+
// 若不增加SliverOverlapInjector,则下方的list顶部会被上方headerSliverBuilder所创建的组件遮住,
93+
// 增加后,类似clear:both效果,使得布局能顺畅衔接
94+
SliverOverlapInjector(
95+
// This is the flip side of the SliverOverlapAbsorber above.
96+
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
97+
context),
98+
),
99+
SliverPadding(
100+
padding: const EdgeInsets.all(8.0),
101+
// In this example, the inner scroll view has
102+
// fixed-height list items, hence the use of
103+
// SliverFixedExtentList. However, one could use any
104+
// sliver widget here, e.g. SliverList or SliverGrid.
105+
sliver: SliverFixedExtentList(
106+
// The items in this example are fixed to 48 pixels
107+
// high. This matches the Material Design spec for
108+
// ListTile widgets.
109+
itemExtent: 48.0,
110+
delegate: SliverChildBuilderDelegate(
111+
(BuildContext context, int index) {
112+
// This builder is called for each child.
113+
// In this example, we just number each list item.
114+
return ListTile(
115+
title: Text('Item $index'),
116+
);
117+
},
118+
// The childCount of the SliverChildBuilderDelegate
119+
// specifies how many children this inner list
120+
// has. In this example, each tab has a list of
121+
// exactly 30 items, but this is arbitrary.
122+
childCount: 30,
123+
),
124+
),
125+
),
126+
],
127+
);
128+
},
129+
),
130+
);
131+
}).toList(),
132+
),
133+
),
134+
);
135+
}
136+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
3+
import 'demo.dart' as Demo;
4+
5+
class Index extends StatefulWidget {
6+
static String title = 'NestedScrollView';
7+
static String mdUrl = 'docs/widget/scrollview/nestedscrollview/index.md';
8+
static String originCodeUrl = 'https://docs.flutter.io/flutter/widgets/Scrollbar-class.html';
9+
10+
@override
11+
_IndexState createState() => new _IndexState();
12+
}
13+
14+
class _IndexState extends State<Index> {
15+
@override
16+
Widget build(BuildContext context) {
17+
return WidgetComp.Index(
18+
title: Index.title,
19+
originCodeUrl: Index.originCodeUrl,
20+
mdUrl: Index.mdUrl,
21+
demoChild: [
22+
Demo.Index(),
23+
]
24+
);
25+
}
26+
}

pubspec.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,14 @@ flutter:
5757
# - images/a_dot_ham.jpeg
5858
assets:
5959
- locale/
60+
- docs/widget/scrollview/customscrollview/
6061
- docs/widget/scrollview/gridview/
6162
- docs/widget/scrollview/listview/
63+
- docs/widget/scrollview/nestedscrollview/
6264
- docs/widget/scrollview/scrollable/
63-
- docs/widget/scrollview/customscrollview/
64-
- docs/widget/scrollview/singlechildscrollview/
6565
- docs/widget/scrollview/scrollbar/
6666
- docs/widget/scrollview/scrollcontroller/
67+
- docs/widget/scrollview/singlechildscrollview/
6768
- docs/widget/regular/row/
6869
- docs/widget/regular/column/
6970
- docs/widget/regular/container/

0 commit comments

Comments
 (0)