In my app i need complex scroll views. As horizontal lists inside of vertical list and animated headers. The code below is a minimalistic sample that makes my problem reproducible on iOS devices.
I have problems with nested scrollviews in flutter. if i use SliverOverlapAbsorber and SliverOverlapInjector the used CupertinoSliverRefreshControl (the progress indicator) doesn't show up on pull down.
So i replaced it with a red Container. It seams like it's shifted to the top so it's below the appbar. When I set pinned to false in the SliverAppBar it's showing correct, but i need the appbar to stay. I don't get what the pinned parameter has to do with that.
Also, if i put less items in my SliverFixedExtentList (let's say 5 instead of 50) the CupertinoSliverRefreshControl it's not possible to pull down at all (no scrolling, also only not working with the overlap observer/injector used).
Can anyone help me, why this is happening or has an alternative for the overlap observer/injector?
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class TestScrollRefresh extends StatefulWidget {
const TestScrollRefresh({Key? key}) : super(key: key);
@override
State<TestScrollRefresh> createState() => _TestScrollRefreshState();
}
class _TestScrollRefreshState extends State<TestScrollRefresh> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool isBoxScrolled) {
return [
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar(
title: Text("Title"),
forceElevated: isBoxScrolled,
pinned: true,
),
),
];
},
body: Builder(
builder: (BuildContext context) {
final innerScrollController = PrimaryScrollController.of(context);
return CustomScrollView(
controller: innerScrollController,
slivers: <Widget>[
_refreshIndicator(),
SliverOverlapInjector(
handle:
NestedScrollView.sliverOverlapAbsorberHandleFor(context),
),
SliverFixedExtentList(
itemExtent: 48.0,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return ListTile(title: Text('Item $index'));
},
childCount: 50,
),
),
],
);
},
),
),
);
}
Future<bool> refresh() async {
print('wait for service to refresh dummy');
await Future<void>.delayed(const Duration(milliseconds: 5000));
return false;
}
_refreshIndicator() {
return CupertinoSliverRefreshControl(
onRefresh: () => refresh(),
builder: (BuildContext context, RefreshIndicatorMode refreshState, double pulledExtent, double refreshTriggerPullDistance, double refreshIndicatorExtent,){
return Container(color: Colors.red,);
},
);
}
}
I was able to address this issue by using the builder property of CupertinoSliverRefreshControl:
CupertinoSliverRefreshControl(
onRefresh: onRefresh,
builder: (context, refreshState, pulledExtent, refreshTriggerPullDistance, refreshIndicatorExtent) {
return Padding(
padding: const EdgeInsets.only(top: 100),
child: CupertinoSliverRefreshControl.buildRefreshIndicator(
context,
refreshState,
pulledExtent,
refreshTriggerPullDistance,
refreshIndicatorExtent,
),
);
},
),
This GitHub comment also helped me better understand the usage of NestedScrollView.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With