[RenderListWheelViewport] Update content dimensions to prevent scroll offset changes (#96102)

diff --git a/packages/flutter/lib/src/rendering/list_wheel_viewport.dart b/packages/flutter/lib/src/rendering/list_wheel_viewport.dart
index 08f5240..b9a8189 100644
--- a/packages/flutter/lib/src/rendering/list_wheel_viewport.dart
+++ b/packages/flutter/lib/src/rendering/list_wheel_viewport.dart
@@ -663,12 +663,10 @@
   /// by [childManager].
   @override
   void performLayout() {
-    final BoxConstraints childConstraints =
-      constraints.copyWith(
-        minHeight: _itemExtent,
-        maxHeight: _itemExtent,
-        minWidth: 0.0,
-      );
+    // Apply the dimensions first in case it changes the scroll offset which
+    // determines what should be shown.
+    offset.applyViewportDimension(_viewportExtent);
+    offset.applyContentDimensions(_minEstimatedScrollExtent, _maxEstimatedScrollExtent);
 
     // The height, in pixel, that children will be visible and might be laid out
     // and painted.
@@ -680,7 +678,7 @@
       visibleHeight *= 2;
 
     final double firstVisibleOffset =
-        offset.pixels + _itemExtent / 2 - visibleHeight / 2;
+      offset.pixels + _itemExtent / 2 - visibleHeight / 2;
     final double lastVisibleOffset = firstVisibleOffset + visibleHeight;
 
     // The index range that we want to spawn children. We find indexes that
@@ -721,6 +719,11 @@
         _destroyChild(firstChild!);
     }
 
+    final BoxConstraints childConstraints = constraints.copyWith(
+        minHeight: _itemExtent,
+        maxHeight: _itemExtent,
+        minWidth: 0.0,
+      );
     // If there is no child at this stage, we add the first one that is in
     // target range.
     if (childCount == 0) {
@@ -759,8 +762,6 @@
       _layoutChild(lastChild!, childConstraints, ++currentLastIndex);
     }
 
-    offset.applyViewportDimension(_viewportExtent);
-
     // Applying content dimensions bases on how the childManager builds widgets:
     // if it is available to provide a child just out of target range, then
     // we don't know whether there's a limit yet, and set the dimension to the
@@ -770,16 +771,16 @@
       ? _minEstimatedScrollExtent
       : indexToScrollOffset(targetFirstIndex);
     final double maxScrollExtent = childManager.childExistsAt(targetLastIndex + 1)
-        ? _maxEstimatedScrollExtent
-        : indexToScrollOffset(targetLastIndex);
+      ? _maxEstimatedScrollExtent
+      : indexToScrollOffset(targetLastIndex);
     offset.applyContentDimensions(minScrollExtent, maxScrollExtent);
   }
 
   bool _shouldClipAtCurrentOffset() {
     final double highestUntransformedPaintY =
-        _getUntransformedPaintingCoordinateY(0.0);
+      _getUntransformedPaintingCoordinateY(0.0);
     return highestUntransformedPaintY < 0.0
-        || size.height < highestUntransformedPaintY + _maxEstimatedScrollExtent + _itemExtent;
+      || size.height < highestUntransformedPaintY + _maxEstimatedScrollExtent + _itemExtent;
   }
 
   @override
diff --git a/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart b/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart
index 31eead2..a7740e9 100644
--- a/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart
+++ b/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart
@@ -766,24 +766,26 @@
     }
   }
 
+  bool _handleScrollNotification(ScrollNotification notification) {
+    if (notification.depth == 0
+        && widget.onSelectedItemChanged != null
+        && notification is ScrollUpdateNotification
+        && notification.metrics is FixedExtentMetrics) {
+      final FixedExtentMetrics metrics = notification.metrics as FixedExtentMetrics;
+      final int currentItemIndex = metrics.itemIndex;
+      if (currentItemIndex != _lastReportedItemIndex) {
+        _lastReportedItemIndex = currentItemIndex;
+        final int trueIndex = widget.childDelegate.trueIndexOf(currentItemIndex);
+        widget.onSelectedItemChanged!(trueIndex);
+      }
+    }
+    return false;
+  }
+
   @override
   Widget build(BuildContext context) {
     return NotificationListener<ScrollNotification>(
-      onNotification: (ScrollNotification notification) {
-        if (notification.depth == 0
-            && widget.onSelectedItemChanged != null
-            && notification is ScrollUpdateNotification
-            && notification.metrics is FixedExtentMetrics) {
-          final FixedExtentMetrics metrics = notification.metrics as FixedExtentMetrics;
-          final int currentItemIndex = metrics.itemIndex;
-          if (currentItemIndex != _lastReportedItemIndex) {
-            _lastReportedItemIndex = currentItemIndex;
-            final int trueIndex = widget.childDelegate.trueIndexOf(currentItemIndex);
-            widget.onSelectedItemChanged!(trueIndex);
-          }
-        }
-        return false;
-      },
+      onNotification: _handleScrollNotification,
       child: _FixedExtentScrollable(
         controller: scrollController,
         physics: widget.physics,
diff --git a/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart b/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart
index 395b56a..ba9b6fe 100644
--- a/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart
+++ b/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart
@@ -230,6 +230,7 @@
     });
 
     testWidgets('child builder with lower and upper limits', (WidgetTester tester) async {
+      // Adjust the content dimensions at the end of `RenderListWheelViewport.performLayout()`
       final List<int> paintedChildren = <int>[];
 
       final FixedExtentScrollController controller =
@@ -285,6 +286,69 @@
   });
 
   group('layout', () {
+    // Regression test for https://github.com/flutter/flutter/issues/90953
+    testWidgets('ListWheelScrollView childDelegate update test 2', (WidgetTester tester) async {
+      final FixedExtentScrollController controller = FixedExtentScrollController( initialItem: 2 );
+      Widget buildFrame(int childCount) {
+        return Directionality(
+          textDirection: TextDirection.ltr,
+          child: ListWheelScrollView.useDelegate(
+            controller: controller,
+            itemExtent: 400.0,
+            onSelectedItemChanged: (_) { },
+            childDelegate: ListWheelChildBuilderDelegate(
+              childCount: childCount,
+              builder: (BuildContext context, int index) {
+                return SizedBox(
+                  width: 400.0,
+                  height: 400.0,
+                  child: Text(index.toString()),
+                );
+              },
+            ),
+          ),
+        );
+      }
+
+      await tester.pumpWidget(buildFrame(5));
+      expect(find.text('0'), findsNothing);
+      expect(tester.renderObject(find.text('1')).attached, true);
+      expect(tester.renderObject(find.text('2')).attached, true);
+      expect(tester.renderObject(find.text('3')).attached, true);
+      expect(find.text('4'), findsNothing);
+
+      // Remove the last 3 items.
+      await tester.pumpWidget(buildFrame(2));
+      expect(tester.renderObject(find.text('0')).attached, true);
+      expect(tester.renderObject(find.text('1')).attached, true);
+      expect(find.text('3'), findsNothing);
+
+      // Add 3 items at the end.
+      await tester.pumpWidget(buildFrame(5));
+      expect(tester.renderObject(find.text('0')).attached, true);
+      expect(tester.renderObject(find.text('1')).attached, true);
+      expect(tester.renderObject(find.text('2')).attached, true);
+      expect(find.text('3'), findsNothing);
+      expect(find.text('4'), findsNothing);
+
+
+      // Scroll to the last item.
+      final TestGesture scrollGesture = await tester.startGesture(const Offset(10.0, 10.0));
+      await scrollGesture.moveBy(const Offset(0.0, -1200.0));
+      await tester.pump();
+      expect(find.text('0'), findsNothing);
+      expect(find.text('1'), findsNothing);
+      expect(find.text('2'), findsNothing);
+      expect(tester.renderObject(find.text('3')).attached, true);
+      expect(tester.renderObject(find.text('4')).attached, true);
+
+      // Remove the last 3 items.
+      await tester.pumpWidget(buildFrame(2));
+      expect(tester.renderObject(find.text('0')).attached, true);
+      expect(tester.renderObject(find.text('1')).attached, true);
+      expect(find.text('3'), findsNothing);
+    });
+
     // Regression test for https://github.com/flutter/flutter/issues/58144
     testWidgets('ListWheelScrollView childDelegate update test', (WidgetTester tester) async {
       final FixedExtentScrollController controller = FixedExtentScrollController();