Repository: rrousselGit/flutter_hooks (dart)

Issue:
onAttach and onDetach is missing on usePageController
[Official](https://api.flutter.dev/flutter/widgets/PageController-class.html) constructor:
`PageController({int initialPage = 0, bool keepPage = true, double viewportFraction = 1.0, ScrollControllerCallback? onAttach, ScrollControllerCallback? onDetach})`

Hook usePageController:
`PageController usePageController( {int initialPage = 0, bool keepPage = true, double viewportFraction = 1.0, List<Object?>? keys} )`

Pull request description:
Fixes #420

Patch:
diff --git a/packages/flutter_hooks/CHANGELOG.md b/packages/flutter_hooks/CHANGELOG.md
index 70640b7..dce500e 100644
--- a/packages/flutter_hooks/CHANGELOG.md
+++ b/packages/flutter_hooks/CHANGELOG.md
@@ -1,6 +1,10 @@
+## Unreleased patch
+
+- Added `onAttach` and `onDetach` to `useScrollController` and `usePageController` (thanks to @whynotmake-it)
+
 ## 0.21.1-pre.1 - 2024-07-08
 
-- Added `useDraggableScrollableController` (@thanks to @dickermoshe)
+- Added `useDraggableScrollableController` (thanks to @dickermoshe)
 - Fix TickerMode not getting muted by hooks (thanks to @dev-tatsuya)
 
 ## 0.21.1-pre.0
diff --git a/packages/flutter_hooks/lib/src/page_controller.dart b/packages/flutter_hooks/lib/src/page_controller.dart
index ea0d794..bbe1673 100644
--- a/packages/flutter_hooks/lib/src/page_controller.dart
+++ b/packages/flutter_hooks/lib/src/page_controller.dart
@@ -8,6 +8,8 @@ PageController usePageController({
   int initialPage = 0,
   bool keepPage = true,
   double viewportFraction = 1.0,
+  ScrollControllerCallback? onAttach,
+  ScrollControllerCallback? onDetach,
   List<Object?>? keys,
 }) {
   return use(
@@ -15,6 +17,8 @@ PageController usePageController({
       initialPage: initialPage,
       keepPage: keepPage,
       viewportFraction: viewportFraction,
+      onAttach: onAttach,
+      onDetach: onDetach,
       keys: keys,
     ),
   );
@@ -25,12 +29,16 @@ class _PageControllerHook extends Hook<PageController> {
     required this.initialPage,
     required this.keepPage,
     required this.viewportFraction,
+    this.onAttach,
+    this.onDetach,
     List<Object?>? keys,
   }) : super(keys: keys);
 
   final int initialPage;
   final bool keepPage;
   final double viewportFraction;
+  final ScrollControllerCallback? onAttach;
+  final ScrollControllerCallback? onDetach;
 
   @override
   HookState<PageController, Hook<PageController>> createState() =>
@@ -43,6 +51,8 @@ class _PageControllerHookState
     initialPage: hook.initialPage,
     keepPage: hook.keepPage,
     viewportFraction: hook.viewportFraction,
+    onAttach: hook.onAttach,
+    onDetach: hook.onDetach,
   );
 
   @override
diff --git a/packages/flutter_hooks/lib/src/scroll_controller.dart b/packages/flutter_hooks/lib/src/scroll_controller.dart
index 7a6a539..1d182cf 100644
--- a/packages/flutter_hooks/lib/src/scroll_controller.dart
+++ b/packages/flutter_hooks/lib/src/scroll_controller.dart
@@ -8,6 +8,8 @@ ScrollController useScrollController({
   double initialScrollOffset = 0.0,
   bool keepScrollOffset = true,
   String? debugLabel,
+  ScrollControllerCallback? onAttach,
+  ScrollControllerCallback? onDetach,
   List<Object?>? keys,
 }) {
   return use(
@@ -15,6 +17,8 @@ ScrollController useScrollController({
       initialScrollOffset: initialScrollOffset,
       keepScrollOffset: keepScrollOffset,
       debugLabel: debugLabel,
+      onAttach: onAttach,
+      onDetach: onDetach,
       keys: keys,
     ),
   );
@@ -25,12 +29,16 @@ class _ScrollControllerHook extends Hook<ScrollController> {
     required this.initialScrollOffset,
     required this.keepScrollOffset,
     this.debugLabel,
+    this.onAttach,
+    this.onDetach,
     List<Object?>? keys,
   }) : super(keys: keys);
 
   final double initialScrollOffset;
   final bool keepScrollOffset;
   final String? debugLabel;
+  final ScrollControllerCallback? onAttach;
+  final ScrollControllerCallback? onDetach;
 
   @override
   HookState<ScrollController, Hook<ScrollController>> createState() =>
@@ -43,6 +51,8 @@ class _ScrollControllerHookState
     initialScrollOffset: hook.initialScrollOffset,
     keepScrollOffset: hook.keepScrollOffset,
     debugLabel: hook.debugLabel,
+    onAttach: hook.onAttach,
+    onDetach: hook.onDetach,
   );
 
   @override


Test patch:
diff --git a/packages/flutter_hooks/test/use_page_controller_test.dart b/packages/flutter_hooks/test/use_page_controller_test.dart
index da4def3..31f0cf9 100644
--- a/packages/flutter_hooks/test/use_page_controller_test.dart
+++ b/packages/flutter_hooks/test/use_page_controller_test.dart
@@ -72,6 +72,9 @@ void main() {
     testWidgets('passes hook parameters to the PageController', (tester) async {
       late PageController controller;
 
+      void onAttach(ScrollPosition position) {}
+      void onDetach(ScrollPosition position) {}
+
       await tester.pumpWidget(
         HookBuilder(
           builder: (context) {
@@ -79,6 +82,8 @@ void main() {
               initialPage: 42,
               keepPage: false,
               viewportFraction: 3.4,
+              onAttach: onAttach,
+              onDetach: onDetach,
             );
 
             return Container();
@@ -89,6 +94,25 @@ void main() {
       expect(controller.initialPage, 42);
       expect(controller.keepPage, false);
       expect(controller.viewportFraction, 3.4);
+      expect(controller.onAttach, onAttach);
+      expect(controller.onDetach, onDetach);
+    });
+
+    testWidgets('onAttach and onDetach are null by default', (tester) async {
+      late PageController controller;
+
+      await tester.pumpWidget(
+        HookBuilder(
+          builder: (context) {
+            controller = usePageController();
+
+            return Container();
+          },
+        ),
+      );
+
+      expect(controller.onAttach, isNull);
+      expect(controller.onDetach, isNull);
     });
 
     testWidgets('disposes the PageController on unmount', (tester) async {
diff --git a/packages/flutter_hooks/test/use_scroll_controller_test.dart b/packages/flutter_hooks/test/use_scroll_controller_test.dart
index 7ae60b4..3ab90b2 100644
--- a/packages/flutter_hooks/test/use_scroll_controller_test.dart
+++ b/packages/flutter_hooks/test/use_scroll_controller_test.dart
@@ -73,6 +73,9 @@ void main() {
         (tester) async {
       late ScrollController controller;
 
+      void onAttach(ScrollPosition position) {}
+      void onDetach(ScrollPosition position) {}
+
       await tester.pumpWidget(
         HookBuilder(
           builder: (context) {
@@ -80,6 +83,8 @@ void main() {
               initialScrollOffset: 42,
               debugLabel: 'Hello',
               keepScrollOffset: false,
+              onAttach: onAttach,
+              onDetach: onDetach,
             );
 
             return Container();
@@ -90,6 +95,24 @@ void main() {
       expect(controller.initialScrollOffset, 42);
       expect(controller.debugLabel, 'Hello');
       expect(controller.keepScrollOffset, false);
+      expect(controller.onAttach, onAttach);
+      expect(controller.onDetach, onDetach);
+    });
+
+    testWidgets('onAttach and onDetach are null by default', (tester) async {
+      late ScrollController controller;
+
+      await tester.pumpWidget(
+        HookBuilder(
+          builder: (context) {
+            controller = useScrollController();
+
+            return Container();
+          },
+        ),
+      );
+      expect(controller.onAttach, isNull);
+      expect(controller.onDetach, isNull);
     });
   });
 }