Reputation:
I have a page in an app that paginates data from firebase firestore. To paginate the data, I use a scroll controller which fetches the data once the user scrolls to the bottom.
The problem is that adding the ScrollController()
to the NestedScrollView()
doesn't work properly.
Adding it to a ListView.builder()
widget in the body of the NestedScrollView()
makes the SliverAppBar()
pinned even though it's not. I also get the following exception:
════════ Exception caught by animation library ═════════════════════════════════
The Scrollbar's ScrollController has no ScrollPosition attached.
════════════════════════════════════════════════════════════════════════════════
The scrollbar is the parent of the ListView.builder()
that has the ScrollController()
attached.
Upvotes: 6
Views: 3419
Reputation: 23
RawScrollbar(
scrollbarOrientation: ScrollbarOrientation.right,
radius: Radius.circular(100.h),
mainAxisMargin: 2.h,
thumbVisibility: true,
controller: Scontroller,
child: ListView.builder(
// primary: true,
controller: Scontroller,
itemCount: _warehouseListedData.value?.map((e) => e["godown"]).toSet().toList().length,
scrollDirection: Axis.vertical,
shrinkWrap: true,
padding: EdgeInsets.all(0.5.h),
itemBuilder: (context, index) {
return Container(
width: double.infinity,
margin: EdgeInsets.all(1.w),
padding: EdgeInsets.symmetric(vertical: 1.h, horizontal: 2.w),
decoration: BoxDecoration(color: Color.fromRGBO(34, 34, 34, 1), borderRadius: BorderRadius.circular(1.h)),
child: Column(
children: [
IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
RichText(
text: TextSpan(
children: [
TextSpan(text: "GODOWN: ", style: TextStyle(fontSize: 18, decoration: TextDecoration.none, color: Colors.red, fontWeight: FontWeight.w500)),
TextSpan(text: "${_warehouseListedData.value?.map((e) => e["godown"]).toSet().toList()[index]}", style: TextStyle(fontSize: 20, decoration: TextDecoration.none, color: Colors.red, fontWeight: FontWeight.w600)),
],
),
),
AspectRatio(
aspectRatio: 1,
child: Container(
decoration: BoxDecoration(borderRadius: BorderRadius.circular(0.5.h), border: Border.all(color: Color.fromARGB(255, 75, 75, 75), width: 2.5), color: Colors.white),
child: Center(
child: Padding(
padding: EdgeInsets.all(1.0.w),
child: Text(
"ALL",
style: TextStyle(fontWeight: FontWeight.w700, decoration: TextDecoration.none),
),
),
),
),
)
],
),
),
SizedBox(
height: 1.h,
),
Column(
children: () {
List<Widget> widgets = [];
var thisGodown = _warehouseListedData.value?.map((e) => e["godown"]).toSet().toList()[index];
var thisGodownCompartments = _warehouseListedData.value
?.map((e) {
if (e["godown"] == thisGodown) {
return e["compartment"];
}
})
.toSet()
.whereType<String>()
.toList();
for (var compartment in thisGodownCompartments!) {
var thisCompartmentLocations = _warehouseListedData.value
?.map((e) {
if (e["godown"] == thisGodown && e["compartment"] == compartment) {
return e["location"];
}
})
.toSet()
.whereType<String>()
.toList();
print(thisCompartmentLocations.toString());
ScrollController sc = ScrollController();
widgets.add(
Container(
height: 6.h,
margin: EdgeInsets.symmetric(horizontal: 0.5.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(1.h),
color: Color.fromARGB(255, 69, 69, 69),
),
child: RawScrollbar(
controller: sc,
thumbVisibility: true,
scrollbarOrientation: ScrollbarOrientation.bottom,
child: ListView.builder(
// primary: true,
controller: sc,
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: thisCompartmentLocations?.length,
itemBuilder: (context, index) {
return AspectRatio(
aspectRatio: 1,
child: Container(
margin: EdgeInsets.symmetric(vertical: 2.w, horizontal: 2.w),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(1.w)),
),
);
},
),
),
), // TODO
);
widgets.add(SizedBox(
height: 1.h,
));
}
// print(thisGodownCompartments.toString());
return widgets;
}(),
)
],
),
);
},
),
)
Sorry I was lazy to destructure. Hope someone finds it useful
The Scrollbar and ListView must contain same ScrollController. The ListView Physics should not be defined
Upvotes: 0
Reputation: 1555
You can use innerControll
by using GlobalKey
like below.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: MyWidget());
}
}
class MyWidget extends StatefulWidget {
MyWidget({Key? key}) : super(key: key);
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
final GlobalKey<NestedScrollViewState> globalKey = GlobalKey();
@override
void initState() {
super.initState();
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
globalKey.currentState!.innerController.addListener(() {
print('notify');
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
key: globalKey,
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return const <Widget>[
SliverAppBar(
title: Text('NestedScrollViewState Demo!'),
),
];
},
body: CustomScrollView(
slivers: [
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int i) => Text(i.toString()),
childCount: 500,
),
),
],
),
),
);
}
}
Upvotes: 10