Revert "update ScrollMetricsNotification (#87421)" (#87693)

This reverts commit 52bf9dbbd72ecc787474da223c32d2368a4ad49e.
diff --git a/packages/flutter/lib/src/widgets/scroll_position.dart b/packages/flutter/lib/src/widgets/scroll_position.dart
index 60e78b3..a227263 100644
--- a/packages/flutter/lib/src/widgets/scroll_position.dart
+++ b/packages/flutter/lib/src/widgets/scroll_position.dart
@@ -558,7 +558,7 @@
       // It isn't safe to trigger the ScrollMetricsNotification if we are in
       // the middle of rendering the frame, the developer is likely to schedule
       // a new frame(build scheduled during frame is illegal).
-      if (!_haveScheduledUpdateNotification) {
+      if (_lastMetrics != null && !_haveScheduledUpdateNotification) {
         scheduleMicrotask(didUpdateScrollMetrics);
         _haveScheduledUpdateNotification = true;
       }
diff --git a/packages/flutter/lib/src/widgets/scrollbar.dart b/packages/flutter/lib/src/widgets/scrollbar.dart
index c91089f..b23d687 100644
--- a/packages/flutter/lib/src/widgets/scrollbar.dart
+++ b/packages/flutter/lib/src/widgets/scrollbar.dart
@@ -1224,16 +1224,25 @@
   @override
   void didChangeDependencies() {
     super.didChangeDependencies();
-    assert(_debugScheduleCheckHasValidScrollPosition());
+    _maybeTriggerScrollbar();
   }
 
-  bool _debugScheduleCheckHasValidScrollPosition() {
-    if (!showScrollbar)
-      return true;
+  // Waits one frame and cause an empty scroll event (zero delta pixels).
+  //
+  // This allows the thumb to show immediately when isAlwaysShown is true.
+  // A scroll event is required in order to paint the thumb.
+  void _maybeTriggerScrollbar() {
     WidgetsBinding.instance!.addPostFrameCallback((Duration duration) {
-      assert(_debugCheckHasValidScrollPosition());
+      final ScrollController? scrollController = widget.controller ?? PrimaryScrollController.of(context);
+      if (showScrollbar) {
+        _fadeoutTimer?.cancel();
+        // Wait one frame and cause an empty scroll event.  This allows the
+        // thumb to show immediately when isAlwaysShown is true. A scroll
+        // event is required in order to paint the thumb.
+        assert(_debugCheckHasValidScrollPosition());
+        scrollController!.position.didUpdateScrollPositionBy(0);
+      }
     });
-    return true;
   }
 
   void _validateInteractions(AnimationStatus status) {
@@ -1356,8 +1365,7 @@
     super.didUpdateWidget(oldWidget);
     if (widget.isAlwaysShown != oldWidget.isAlwaysShown) {
       if (widget.isAlwaysShown == true) {
-        assert(_debugScheduleCheckHasValidScrollPosition());
-        _fadeoutTimer?.cancel();
+        _maybeTriggerScrollbar();
         _fadeoutAnimationController.animateTo(1.0);
       } else {
         _fadeoutAnimationController.reverse();
diff --git a/packages/flutter/test/cupertino/scrollbar_test.dart b/packages/flutter/test/cupertino/scrollbar_test.dart
index 0359f11..bbdfa21 100644
--- a/packages/flutter/test/cupertino/scrollbar_test.dart
+++ b/packages/flutter/test/cupertino/scrollbar_test.dart
@@ -5,7 +5,6 @@
 import 'dart:ui' as ui;
 
 import 'package:flutter/cupertino.dart';
-import 'package:flutter/foundation.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_test/flutter_test.dart';
 
@@ -390,16 +389,9 @@
         );
       }
 
-      final FlutterExceptionHandler? handler = FlutterError.onError;
-      FlutterErrorDetails? error;
-      FlutterError.onError = (FlutterErrorDetails details) {
-        error = details;
-      };
-
       await tester.pumpWidget(viewWithScroll());
-      expect(error, isNotNull);
-
-      FlutterError.onError = handler;
+      final AssertionError exception = tester.takeException() as AssertionError;
+      expect(exception, isAssertionError);
     },
   );
 
diff --git a/packages/flutter/test/widgets/scroll_notification_test.dart b/packages/flutter/test/widgets/scroll_notification_test.dart
index e56b4cd..1f9d512 100644
--- a/packages/flutter/test/widgets/scroll_notification_test.dart
+++ b/packages/flutter/test/widgets/scroll_notification_test.dart
@@ -21,9 +21,8 @@
       );
     }
     await tester.pumpWidget(buildFrame(1200.0));
-    expect(events.length, 1);
+    expect(events.length, 0);
 
-    events.clear();
     await tester.pumpWidget(buildFrame(1000.0));
     // Change the content dimensions will trigger a new event.
     expect(events.length, 1);
diff --git a/packages/flutter/test/widgets/scrollbar_test.dart b/packages/flutter/test/widgets/scrollbar_test.dart
index c055842..4008057 100644
--- a/packages/flutter/test/widgets/scrollbar_test.dart
+++ b/packages/flutter/test/widgets/scrollbar_test.dart
@@ -4,7 +4,6 @@
 
 import 'dart:ui' as ui;
 
-import 'package:flutter/foundation.dart';
 import 'package:flutter/src/physics/utils.dart' show nearEqual;
 import 'package:flutter/widgets.dart';
 import 'package:flutter_test/flutter_test.dart';
@@ -1144,12 +1143,6 @@
   });
 
   testWidgets('RawScrollbar.isAlwaysShown asserts that a ScrollPosition is attached', (WidgetTester tester) async {
-    final FlutterExceptionHandler? handler = FlutterError.onError;
-    FlutterErrorDetails? error;
-    FlutterError.onError = (FlutterErrorDetails details) {
-      error = details;
-    };
-
     await tester.pumpWidget(
       Directionality(
         textDirection: TextDirection.ltr,
@@ -1170,15 +1163,12 @@
       ),
     );
     await tester.pumpAndSettle();
-
-    expect(error, isNotNull);
-    final AssertionError exception = error!.exception as AssertionError;
+    final AssertionError exception = tester.takeException() as AssertionError;
+    expect(exception, isAssertionError);
     expect(
       exception.message,
       contains("The Scrollbar's ScrollController has no ScrollPosition attached."),
     );
-
-    FlutterError.onError = handler;
   });
 
   testWidgets('Interactive scrollbars should have a valid scroll controller', (WidgetTester tester) async {