I'm just trying out the new river_pod, flutter state management library. My goal here is simple. GestureDetector
in the main page listens to vertical drags and updates the animation controller accordingly. And I'd like to listen to this animation somewhere else. I have written the following code, and it's working as expected. But I don't feel like I'm initializing the provider in the right way.
// a custom notifier class
class AnimationNotifier extends ChangeNotifier {
final AnimationController _animationController;
AnimationNotifier(this._animationController) {
_animationController.addListener(_onAnimationControllerChanged);
}
void forward() => _animationController.forward();
void reverse() => _animationController.reverse();
void _onAnimationControllerChanged() {
notifyListeners();
}
@override
void dispose() {
_animationController.removeListener(_onAnimationControllerChanged);
super.dispose();
}
double get value => _animationController.value;
}
// provider variable, (not initialized here)
var animationProvider;
// main Widget
class GestureControlledAnimationDemo extends StatefulWidget {
@override
_GestureControlledAnimationDemoState createState() =>
_GestureControlledAnimationDemoState();
}
class _GestureControlledAnimationDemoState
extends State<GestureControlledAnimationDemo>
with SingleTickerProviderStateMixin {
AnimationController _controller;
double get maxHeight => 420.0;
@override
void initState() {
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
);
// provider is initialized here
animationProvider = ChangeNotifierProvider((_) {
return AnimationNotifier(_controller);
});
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return CustomScaffold(
title: 'GestureControlled',
body: GestureDetector(
onVerticalDragUpdate: _handleDragUpdate,
onVerticalDragEnd: _handleDragEnd,
child: Container(
color: Colors.red,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Yo',
style: TextStyle(color: Colors.white),
),
NotifierTest(),
],
),
),
),
),
);
}
void _handleDragUpdate(DragUpdateDetails details) {
_controller.value -= details.primaryDelta / maxHeight;
}
void _handleDragEnd(DragEndDetails details) {
if (_controller.isAnimating ||
_controller.status == AnimationStatus.completed) return;
final double flingVelocity =
details.velocity.pixelsPerSecond.dy / maxHeight;
if (flingVelocity < 0.0) {
_controller.fling(velocity: max(2.0, -flingVelocity));
} else if (flingVelocity > 0.0) {
_controller.fling(velocity: min(-2.0, -flingVelocity));
} else {
_controller.fling(velocity: _controller.value < 0.5 ? -2.0 : 2.0);
}
}
}
// Widget which uses the provider
class NotifierTest extends HookWidget {
@override
Widget build(BuildContext context) {
final animationNotifier = useProvider(animationProvider);
double count = animationNotifier.value * 1000.0;
return Container(
child: Text(
'${count.floor()}',
style: TextStyle(color: Colors.white),
),
);
}
}
Since an animation controller instance is required to create an instance of AnimationNotifier
, this can be done only after _controller
initialization. So in the initState()
, I've initialized both _controller
and animationProvider
. Is this the right way to use riverpod Provider
?
If not, what modifications can be made?