I have simplified my real app into the following code below to show the problem. I am basically trying to show the scroll offset of a list view on another widget (the real app is a lot more complex where the widget does other stuff with that offset).
I am returning the ViewController() as the body of my Scaffold in the main.dart. In my ViewController below, I have a stack which contains a ListView and a Text. I want the controller for the ListView to update the Text using the ChangeNotifierProvider. It doesn't work for some reason.
My ChangeNotifier is the scrollProvider which has been declared as a variable of the entire ViewController and I am passing the same scrollProvider into the ChangeNotifierProvider and also printing from the same.
What am I doing wrong?
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ViewController extends StatefulWidget {
const ViewController({super.key});
@override
State<ViewController> createState() => _ViewControllerState();
}
class _ViewControllerState extends State<ViewController> {
final scrollController = ScrollController();
final scrollProvider = ScrollProvider();
@override
void initState() {
scrollController.addListener(scrollHandler);
super.initState();
}
@override
void dispose() {
scrollController.removeListener(scrollHandler);
super.dispose();
}
void scrollHandler() {
scrollProvider.setCurrentOffset(scrollController.offset);
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
ListView.builder(
controller: scrollController,
itemBuilder: ((context, index) {
return Text(
"Index: $index",
style: const TextStyle(fontSize: 40),
);
}),
itemCount: 100,
),
Positioned(
left: 0,
bottom: 0,
right: 0,
child: CupertinoButton(
onPressed: (() {}),
child: ChangeNotifierProvider(
create: ((_) => scrollProvider),
child: Text(
"Offset: ${scrollProvider.currentOffset}",
// "Offset: ${Provider.of<ScrollProvider>(context, listen: false).currentOffset}",
style: const TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
backgroundColor: Colors.black,
),
),
),
),
),
],
);
}
}
class ScrollProvider extends ChangeNotifier {
double? currentOffset;
void setCurrentOffset(valueToSet) {
if (currentOffset != valueToSet) {
currentOffset = valueToSet;
print("currentOffset: $currentOffset");
notifyListeners();
}
}
}
You need to take care of two things:
If you want to create a provider from an already existing value, use the ChangeNotifierProvider.value named constructor.
Wrap your
Textwidget into aConsumer<ScrollProvider>so that it gets notified whencurrentOffsetis changed.(And always call
super.initStateininitStatein the first line and do your own logic afterwards.)With some modifications in your code this is an example of how to get it working: