Repository: flutter
Issue: TwoDimensionalScrollView lag for small-many grid
Labels: framework,c: performance,has reproducible steps,P2,team-framework,triaged-framework,found in release: 3.24,found in release: 3.25

### Steps to reproduce

You can checkout [dartpad](https://dartpad.dev/?id=01997ebded25bb83b9c297d8c25791f3)

### Code sample

<details open><summary>Code sample</summary>

```dart
import 'package:flutter/material.dart';

import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'dart:math' as math;

///*I was playing with 2D gridView and my use-case is to render thousands of grids,
/// it is good <k and large grid size(>100px).
/// but it keeps lagging once I have small grids(<20px)
/// idk if it is for heavy computation on layoutChildSequence,
/// I am wondering is there anyway of optimizing RenderTwoDimensionalViewport for small many grid.
/// !https://github.com/yeasin50/game_of_life/blob/master/lib/src/presentation/widgets/two_dimensional_gridview.dart
///
/// Create a grid view on TwoDimensionalScrollView
///
/// ```dart
///  TwoDimensionalGridView(
///   gridDimension: 20,
///   diagonalDragBehavior: DiagonalDragBehavior.free,
///   cacheExtent: 500,
///   delegate: TwoDimensionalChildBuilderDelegate(
///     maxXIndex: 130,
///     maxYIndex: 130,
///     builder: (context, vicinity) {
///       return Container(
///         height: 20,
///         width: 20,
///         color: Colors.primaries[(vicinity.xIndex + vicinity.yIndex) % Colors.primaries.length],
///         alignment: Alignment.center,
///         child: Text(
///           vicinity.toString(),
///         ),
///       );
///     },
///   ),
/// ),
/// ```
/// 
@Deprecated("Not usable for large items, use [TwoDimensionalCustomPaintGridView] instead")
class TwoDimensionalGridView extends TwoDimensionalScrollView {
  const TwoDimensionalGridView({
    super.key,
    required super.delegate,
    required this.gridDimension,
    super.primary,
    super.mainAxis = Axis.vertical,
    super.verticalDetails = const ScrollableDetails.vertical(),
    super.horizontalDetails = const ScrollableDetails.horizontal(),
    super.cacheExtent,
    super.diagonalDragBehavior = DiagonalDragBehavior.none,
    super.dragStartBehavior = DragStartBehavior.start,
    super.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
    super.clipBehavior = Clip.hardEdge,
  });

  /// size of the grid
  final double gridDimension;

  @override
  Widget buildViewport(
    BuildContext context,
    ViewportOffset verticalOffset,
    ViewportOffset horizontalOffset,
  ) {
    return TwoDimensionalGridViewPort(
      gridDimension: gridDimension,
      cacheExtent: cacheExtent,
      clipBehavior: clipBehavior,
      verticalOffset: verticalOffset,
      verticalAxisDirection: AxisDirection.down,
      horizontalAxisDirection: AxisDirection.right,
      horizontalOffset: horizontalOffset,
      delegate: delegate,
      mainAxis: mainAxis,
    );
  }
}

class TwoDimensionalGridViewPort extends TwoDimensionalViewport {
  const TwoDimensionalGridViewPort({
    super.key,
    required super.verticalOffset,
    required super.verticalAxisDirection,
    required super.horizontalOffset,
    required super.horizontalAxisDirection,
    required super.delegate,
    required super.mainAxis,
    super.cacheExtent,
    super.clipBehavior = Clip.hardEdge,
    required this.gridDimension,
  });

  final double gridDimension;

  @override
  RenderTwoDimensionalViewport createRenderObject(BuildContext context) {
    return RenderTreeViewPostT(
      gridDimension: gridDimension,
      horizontalOffset: horizontalOffset,
      horizontalAxisDirection: horizontalAxisDirection,
      verticalOffset: verticalOffset,
      verticalAxisDirection: verticalAxisDirection,
      delegate: delegate,
      mainAxis: mainAxis,
      childManager: context as TwoDimensionalChildManager,
    );
  }

  @override
  void updateRenderObject(BuildContext context, covariant RenderTwoDimensionalViewport renderObject) {
    super.updateRenderObject(context, renderObject);
  }
}

class RenderTreeViewPostT extends RenderTwoDimensionalViewport {
  RenderTreeViewPostT({
    required super.horizontalOffset,
    required super.horizontalAxisDirection,
    required super.verticalOffset,
    required super.verticalAxisDirection,
    required super.delegate,
    required super.mainAxis,
    required super.childManager,
    required this.gridDimension,
  });

  ///ig there should be way to get from child instead, while I will have same size grid, so ignoring
  final double gridDimension;

  @override
  void layoutChildSequence() {
    // FIXME:   The laggy ui
    final double horizontalPixels = horizontalOffset.pixels;
    final double verticalPixels = verticalOffset.pixels;

    final viewPortWidth = viewportDimension.width + cacheExtent;
    final viewPortHeight = viewportDimension.height + cacheExtent;

    final TwoDimensionalChildBuilderDelegate builderDelegate = delegate as TwoDimensionalChildBuilderDelegate;

    final int maxRowIndex = builderDelegate.maxYIndex!;
    final int maxColIndex = builderDelegate.maxXIndex!;

    final int leadingColumn = math.max((horizontalPixels / gridDimension).floor(), 0);
    final int leadingRow = math.max((verticalPixels / gridDimension).floor(), 0);

    final int trailingColumn = math.min(((horizontalPixels + viewPortWidth) / gridDimension).ceil(), maxColIndex);
    final int trailingRow = math.min(((verticalPixels + viewPortHeight) / gridDimension).ceil(), maxRowIndex);

    double xLayoutOffset = (leadingColumn * gridDimension) - horizontalPixels;
    for (int x = leadingColumn; x < trailingColumn; x++) {
      double yLayoutOffset = (leadingRow * gridDimension) - verticalPixels;
      for (int y = leadingRow; y < trailingRow; y++) {
        final ChildVicinity childVicinity = ChildVicinity(xIndex: x, yIndex: y);
        final RenderBox child = buildOrObtainChildFor(childVicinity)!;
        child.layout(constraints.loosen());

        parentDataOf(child).layoutOffset = Offset(xLayoutOffset, yLayoutOffset);
        yLayoutOffset += gridDimension;
      }
      xLayoutOffset += gridDimension;
    }

    final double verticalExtent = gridDimension * (maxRowIndex + 1.0);
    verticalOffset.applyContentDimensions(0, (verticalExtent - viewportDimension.height));

    final double horizontalExtent = gridDimension * (maxColIndex + 1);
    horizontalOffset.applyContentDimensions(0, (horizontalExtent - viewportDimension.width));
  }
}

void main() {
  runApp(MaterialApp(
    debugShowCheckedModeBanner: false,
    home: MyApp(),
    scrollBehavior: MaterialScrollBehavior().copyWith(
      dragDevices: {
        PointerDeviceKind.mouse,
        PointerDeviceKind.touch,
        PointerDeviceKind.stylus,
        PointerDeviceKind.unknown
      },
    ),
  ));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: TwoDimensionalGridView(
        gridDimension: 20,
        diagonalDragBehavior: DiagonalDragBehavior.free,
        cacheExtent: 500,
        delegate: TwoDimensionalChildBuilderDelegate(
          maxXIndex: 200,
          maxYIndex: 100,
          builder: (context, vicinity) {
            return SizedBox.expand(
              child: ColoredBox(
                key: ValueKey(vicinity),
                color: Colors.primaries[(vicinity.xIndex + vicinity.yIndex) % Colors.primaries.length ~/ 2],
              ),
            );
          },
        ),
      ),
    );
  }
}

```

</details>


### What target platforms are you seeing this bug on?

Android, Web, Windows

### OS/Browser name and version | Device information

Any,  Windows10

### Does the problem occur on emulator/simulator as well as on physical devices?

Yes

### Logs

_No response_

### Flutter Doctor output

<details open><summary>Doctor output</summary>

```console
[√] Flutter (Channel stable, 3.24.1, on Microsoft Windows [Version 10.0.19045.4780], locale en-US)
    • Flutter version 3.24.1 on channel stable at P:\symlinks_portal\fvm_cache\versions\3.24.1
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 5874a72aa4 (2 weeks ago), 2024-08-20 16:46:00 -0500
    • Engine revision c9b9d5780d
    • Dart version 3.5.1
    • DevTools version 2.37.2

[√] Windows Version (Installed version of Windows is version 10 or higher)
```

</details>