https://pub.dev/packages/extended_nested_scroll_view
中文说明:https://github.com/fluttercandies/extended_nested_scroll_view/blob/master/README-ZH.md
扩展NestedScrollView来修复了下面的问题
1.pinned的Header的问题
2.body里面TabView列表滚动同步,互相影响的问题
3.下拉刷新不能工作
4.在NestedScrollView的body中不通过设置ScrollController(设置了会跟内部Controller冲突)来完成下拉刷新,增量加载,滚动到顶部
- Flutter 扩展NestedScrollView (一)Pinned头引起的bug解决
- Flutter 扩展NestedScrollView (二)列表滚动同步解决
- Flutter 扩展NestedScrollView (三)下拉刷新的解决
安装依赖
dependencies:
extended_nested_scroll_view: ^2.0.0
导入
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
示例
import 'dart:async';
import 'package:app1/utils/Base.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart' as extended;
class NestedScrollViewPage extends StatefulWidget {
@override
_NestedScrollViewPageState createState() => _NestedScrollViewPageState();
}
class _NestedScrollViewPageState extends State<NestedScrollViewPage>
with SingleTickerProviderStateMixin {
TabController _tabController; //tab控制器
int _tabIndex = 0; //Tab索引
int _listCount = 10; //tab-列表数量
int _gridCount = 10; //tab-表格数量
@override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this);
}
@override
void dispose() {
super.dispose();
_tabController.dispose();
}
@override
Widget build(BuildContext context) {
// 在NestedScrollView当中,有2个ScrollController.
// 一个是inner,一个outer。
// outer是负责headerSliverBuilder里面的滚动widgets
// inner是负责body里面的滚动widgets 当outer滚动到底了之后,就会看看inner里面是否有能滚动的东东,开始滚动。
return extended.NestedScrollView(
// 在pinnedHeaderSliverHeightBuilder回调中设置全部pinned的header的高度,
// demo里面高度为 状态栏高度+SliverAppbar的高度
pinnedHeaderSliverHeightBuilder: () {
return MediaQuery.of(context).padding.top + kToolbarHeight;
},
// innerScrollPositionKeyBuilder回调中给出当前tab的key.
innerScrollPositionKeyBuilder: () {
if (_tabController.index == 0) {
return Key('tab0');
} else {
return Key('tab1');
}
},
headerSliverBuilder: (context, innerBoxIsScrolled) {
return [
SliverAppBar(
title: Text("NestedScrollView"),
pinned: true,
expandedHeight: 120.0,
flexibleSpace: SingleChildScrollView(
physics: NeverScrollableScrollPhysics(),
child: Container(),
),
floating: false,
),
];
},
body: Column(
children: [
Container(
height: 50,
color: Colors.green,
child: TabBar(
controller: _tabController,
onTap: (index) {
setState(() {
_tabIndex = index;
});
},
tabs: [
Tab(text: 'List'),
Tab(text: 'Grid'),
],
),
),
Expanded(
child: IndexedStack(
index: _tabIndex,
children: [
// TabbarView里面的列表,使用NestedScrollViewInnerScrollPositionKeyWidget包住,
// 并且设置唯一key, 这个key跟列表是第几个tab有关系。
extended.NestedScrollViewInnerScrollPositionKeyWidget(
Key('Tab0'),
EasyRefresh(
child: ListView.builder(
padding: EdgeInsets.all(0.0),
itemBuilder: (context, index) {
return Container(
color: Color(Base.getRandomColor()),
height: 100,
child: Text('我是列表文本 ${index + 1}', textScaleFactor: 3),
);
},
itemCount: _listCount,
),
onRefresh: () async {
await Future.delayed(Duration(seconds: 2), () {
if (mounted) {
setState(() {
_listCount = 10;
});
}
});
},
onLoad: () async {
await Future.delayed(Duration(seconds: 2), () {
if (mounted) {
setState(() {
_listCount += 10;
});
}
});
},
),
),
extended.NestedScrollViewInnerScrollPositionKeyWidget(
Key('Tab1'),
EasyRefresh(
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 6 / 7,
),
itemBuilder: (context, index) {
return Container(
color: Color(Base.getRandomColor()),
height: 100,
child: Text('我是表格文本 ${index + 1}', textScaleFactor: 2),
);
},
itemCount: _gridCount,
),
onRefresh: () async {
await Future.delayed(Duration(seconds: 2), () {
if (mounted) {
setState(() {
_gridCount = 10;
});
}
});
},
onLoad: () async {
await Future.delayed(Duration(seconds: 2), () {
if (mounted) {
setState(() {
_gridCount += 10;
});
}
});
},
),
),
],
),
),
],
),
);
}
}