flutter icon indicating copy to clipboard operation
flutter copied to clipboard

RenderTwoDimensionalViewport.buildOrObtainChildFor throws assertion failure for a valid vicinity

Open Amir-P opened this issue 2 years ago • 4 comments

Steps to reproduce

  1. Run the example
  2. Press on FAB
  3. Press again on FAB

Expected results

You should see the initial widgets on screen since pressing on FAB for second time returns to the initial state.

Actual results

Nothing renders on screen and you'll get an exception log in console due to assertion failure in RenderTwoDimensionalViewport.parentDataOf

Code sample

Code sample

https://dartpad.dev/?id=2c4cc823007d1dc0a9727be611e62f2c

Logs

Logs
════════ Exception caught by rendering library ═════════════════════════════════
The following assertion was thrown during performLayout():
'package:flutter/src/widgets/two_dimensional_viewport.dart': Failed assertion: line 783 pos 12: '_children.containsValue(child)': is not true.

Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
  https://github.com/flutter/flutter/issues/new?template=2_bug.yml

The relevant error-causing widget was:
    TwoDimensionalGridViewport TwoDimensionalGridViewport:file:///main.dart:127:12

When the exception was thrown, this was the stack:
#2      RenderTwoDimensionalViewport.parentDataOf (package:flutter/src/widgets/two_dimensional_viewport.dart:783:12)
#3      RenderTwoDimensionalViewport._moveChild (package:flutter/src/widgets/two_dimensional_viewport.dart:1630:62)
#4      _TwoDimensionalViewportElement.moveRenderObjectChild (package:flutter/src/widgets/two_dimensional_viewport.dart:265:18)
#5      RenderObjectElement.updateSlot (package:flutter/src/widgets/framework.dart:6542:35)
#6      Element.updateSlotForChild.visit (package:flutter/src/widgets/framework.dart:4153:15)
#7      Element.updateSlotForChild.visit (package:flutter/src/widgets/framework.dart:4156:9)
#8      Element.updateSlotForChild.visit (package:flutter/src/widgets/framework.dart:4156:9)
#9      Element.updateSlotForChild.visit (package:flutter/src/widgets/framework.dart:4156:9)
#10     Element.updateSlotForChild (package:flutter/src/widgets/framework.dart:4159:5)
#11     Element.updateChild (package:flutter/src/widgets/framework.dart:3799:11)
#12     _TwoDimensionalViewportElement._buildChild.<anonymous closure> (package:flutter/src/widgets/two_dimensional_viewport.dart:313:33)
#13     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2835:19)
#14     _TwoDimensionalViewportElement._buildChild (package:flutter/src/widgets/two_dimensional_viewport.dart:307:12)
#15     RenderTwoDimensionalViewport.buildOrObtainChildFor.<anonymous closure> (package:flutter/src/widgets/two_dimensional_viewport.dart:1427:23)
#16     RenderObject.invokeLayoutCallback.<anonymous closure> (package:flutter/src/rendering/object.dart:2657:59)
#17     PipelineOwner._enableMutationsToDirtySubtrees (package:flutter/src/rendering/object.dart:1071:15)
#18     RenderObject.invokeLayoutCallback (package:flutter/src/rendering/object.dart:2657:14)
#19     RenderTwoDimensionalViewport.buildOrObtainChildFor (package:flutter/src/widgets/two_dimensional_viewport.dart:1426:7)
#20     RenderTwoDimensionalGridViewport.layoutChildSequence (package:example/main.dart:227:34)
#21     RenderTwoDimensionalViewport.performLayout (package:flutter/src/widgets/two_dimensional_viewport.dart:1252:5)
#22     RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2385:7)
#23     PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1025:18)
#24     PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1038:15)
#25     RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:591:23)
#26     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:986:13)
#27     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:457:5)
#28     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1325:15)
#29     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1255:9)
#30     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1113:5)
#31     _invoke (dart:ui/hooks.dart:312:13)
#32     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:383:5)
#33     _drawFrame (dart:ui/hooks.dart:283:31)
(elided 2 frames from class _AssertionError)

The following RenderObject was being processed when the exception was fired: RenderTwoDimensionalGridViewport#9d954 NEEDS-LAYOUT
    needs compositing
    parentData: <none> (can use size)
    constraints: BoxConstraints(0.0<=w<=984.0, 0.0<=h<=691.0)
    layer: OffsetLayer#dc1bd
        engine layer: OffsetEngineLayer#3c122
        handles: 2
        offset: Offset(0.0, 56.0)
    size: Size(984.0, 691.0)
    (xIndex: 1, yIndex: 1): RenderRepaintBoundary#71f4f NEEDS-PAINT
        needs compositing
        parentData: vicinity=(xIndex: 1, yIndex: 1); layoutOffset=Offset(200.0, 200.0); paintOffset=Offset(0.0, 0.0); visible - paintExtent=Size(200.0, 200.0);
        constraints: BoxConstraints(0.0<=w<=984.0, 0.0<=h<=691.0)
        layer: OffsetLayer#8295b
            engine layer: OffsetEngineLayer#415f8
            handles: 2
            offset: Offset(0.0, 0.0)
        size: Size(200.0, 200.0)
        metrics: 66.7% useful (1 bad vs 2 good)
        diagnosis: insufficient data to draw conclusion (less than five repaints)
        child: RenderConstrainedBox#f153a relayoutBoundary=up1 NEEDS-PAINT
            parentData: <none> (can use size)
            constraints: BoxConstraints(0.0<=w<=984.0, 0.0<=h<=691.0)
            size: Size(200.0, 200.0)
            additionalConstraints: BoxConstraints(w=200.0, h=200.0)
            child: _RenderColoredBox#e6003 NEEDS-PAINT
                parentData: <none> (can use size)
                constraints: BoxConstraints(w=200.0, h=200.0)
                size: Size(200.0, 200.0)
                behavior: opaque
                child: RenderPositionedBox#d4659
                    parentData: <none> (can use size)
                    constraints: BoxConstraints(w=200.0, h=200.0)
                    size: Size(200.0, 200.0)
                    alignment: Alignment.center
                    textDirection: ltr
                    widthFactor: expand
                    heightFactor: expand
RenderObject: RenderTwoDimensionalGridViewport#9d954 NEEDS-LAYOUT
    needs compositing
    parentData: <none> (can use size)
    constraints: BoxConstraints(0.0<=w<=984.0, 0.0<=h<=691.0)
    layer: OffsetLayer#dc1bd
        engine layer: OffsetEngineLayer#3c122
        handles: 2
        offset: Offset(0.0, 56.0)
    size: Size(984.0, 691.0)
    (xIndex: 1, yIndex: 1): RenderRepaintBoundary#71f4f NEEDS-PAINT
        needs compositing
        parentData: vicinity=(xIndex: 1, yIndex: 1); layoutOffset=Offset(200.0, 200.0); paintOffset=Offset(0.0, 0.0); visible - paintExtent=Size(200.0, 200.0);
        constraints: BoxConstraints(0.0<=w<=984.0, 0.0<=h<=691.0)
        layer: OffsetLayer#8295b
            engine layer: OffsetEngineLayer#415f8
            handles: 2
            offset: Offset(0.0, 0.0)
        size: Size(200.0, 200.0)
        metrics: 66.7% useful (1 bad vs 2 good)
        diagnosis: insufficient data to draw conclusion (less than five repaints)
        child: RenderConstrainedBox#f153a relayoutBoundary=up1 NEEDS-PAINT
            parentData: <none> (can use size)
            constraints: BoxConstraints(0.0<=w<=984.0, 0.0<=h<=691.0)
            size: Size(200.0, 200.0)
            additionalConstraints: BoxConstraints(w=200.0, h=200.0)
            child: _RenderColoredBox#e6003 NEEDS-PAINT
                parentData: <none> (can use size)
                constraints: BoxConstraints(w=200.0, h=200.0)
                size: Size(200.0, 200.0)
                behavior: opaque
                child: RenderPositionedBox#d4659
                    parentData: <none> (can use size)
                    constraints: BoxConstraints(w=200.0, h=200.0)
                    size: Size(200.0, 200.0)
                    alignment: Alignment.center
                    textDirection: ltr
                    widthFactor: expand
                    heightFactor: expand
════════════════════════════════════════════════════════════════════════════════

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.16.1, on macOS 14.2.1 23C71 darwin-arm64, locale
    en-US)
    • Flutter version 3.16.1 on channel stable at /flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 7f20e5d18c (6 weeks ago), 2023-11-27 09:47:30 -0800
    • Engine revision 22b600f240
    • Dart version 3.2.1
    • DevTools version 2.28.3

Amir-P avatar Jan 08 '24 11:01 Amir-P

Reproducible using the code sample provided in the dartpad shared above (pasted below for easy access).

code sample
// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:math' as math;

import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      scrollBehavior: const MaterialScrollBehavior().copyWith(
        // Mouse dragging enabled for this demo
        dragDevices: PointerDeviceKind.values.toSet(),
      ),
      debugShowCheckedModeBanner: false,
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  final String title;

  const MyHomePage({
    Key? key,
    required this.title,
  }) : super(key: key);

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

final vicinityToKey1 = <ChildVicinity, String>{
  const ChildVicinity(xIndex: 1, yIndex: 1): '1',
  const ChildVicinity(xIndex: 1, yIndex: 2): '2',
};

final vicinityToKey2 = <ChildVicinity, String>{
   const ChildVicinity(xIndex: 0, yIndex: 0): '1',
  const ChildVicinity(xIndex: 1, yIndex: 1): '2',
};

class _MyHomePageState extends State<MyHomePage> {
  late Map<ChildVicinity, String> vicinityToKey = vicinityToKey1;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      floatingActionButton: FloatingActionButton(
        onPressed: () => setState(() {
          if (vicinityToKey == vicinityToKey1) {
            vicinityToKey = vicinityToKey2;
          } else {
            vicinityToKey = vicinityToKey1;
          }
        }),
      ),
      body: TwoDimensionalGridView(
        diagonalDragBehavior: DiagonalDragBehavior.free,
        delegate: TwoDimensionalChildBuilderDelegate(
            maxXIndex: 30,
            maxYIndex: 30,
            addAutomaticKeepAlives: false,
            addRepaintBoundaries: false,
            builder: (BuildContext context, ChildVicinity vicinity) {
              final key = vicinityToKey[vicinity];
              if (key != null) {
                return AutomaticKeepAlive(
                  key: ValueKey(key),
                  child: RepaintBoundary(
                    child: Container(
                      color: vicinity.xIndex.isEven && vicinity.yIndex.isEven
                          ? Colors.amber[50]
                          : (vicinity.xIndex.isOdd && vicinity.yIndex.isOdd
                              ? Colors.purple[50]
                              : null),
                      height: 200,
                      width: 200,
                      child: Center(child: Text(key)),
                    ),
                  ),
                );
              }
              return null;
            }),
      ),
    );
  }
}

class TwoDimensionalGridView extends TwoDimensionalScrollView {
  const TwoDimensionalGridView({
    super.key,
    super.primary,
    super.mainAxis = Axis.vertical,
    super.verticalDetails = const ScrollableDetails.vertical(),
    super.horizontalDetails = const ScrollableDetails.horizontal(),
    required TwoDimensionalChildBuilderDelegate delegate,
    super.cacheExtent,
    super.diagonalDragBehavior = DiagonalDragBehavior.none,
    super.dragStartBehavior = DragStartBehavior.start,
    super.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
    super.clipBehavior = Clip.hardEdge,
  }) : super(delegate: delegate);

  @override
  Widget buildViewport(
    BuildContext context,
    ViewportOffset verticalOffset,
    ViewportOffset horizontalOffset,
  ) {
    return TwoDimensionalGridViewport(
      horizontalOffset: horizontalOffset,
      horizontalAxisDirection: horizontalDetails.direction,
      verticalOffset: verticalOffset,
      verticalAxisDirection: verticalDetails.direction,
      mainAxis: mainAxis,
      delegate: delegate as TwoDimensionalChildBuilderDelegate,
      cacheExtent: cacheExtent,
      clipBehavior: clipBehavior,
    );
  }
}

class TwoDimensionalGridViewport extends TwoDimensionalViewport {
  const TwoDimensionalGridViewport({
    super.key,
    required super.verticalOffset,
    required super.verticalAxisDirection,
    required super.horizontalOffset,
    required super.horizontalAxisDirection,
    required TwoDimensionalChildBuilderDelegate super.delegate,
    required super.mainAxis,
    super.cacheExtent,
    super.clipBehavior = Clip.hardEdge,
  });

  @override
  RenderTwoDimensionalViewport createRenderObject(BuildContext context) {
    return RenderTwoDimensionalGridViewport(
      horizontalOffset: horizontalOffset,
      horizontalAxisDirection: horizontalAxisDirection,
      verticalOffset: verticalOffset,
      verticalAxisDirection: verticalAxisDirection,
      mainAxis: mainAxis,
      delegate: delegate as TwoDimensionalChildBuilderDelegate,
      childManager: context as TwoDimensionalChildManager,
      cacheExtent: cacheExtent,
      clipBehavior: clipBehavior,
    );
  }

  @override
  void updateRenderObject(
    BuildContext context,
    RenderTwoDimensionalGridViewport renderObject,
  ) {
    renderObject
      ..horizontalOffset = horizontalOffset
      ..horizontalAxisDirection = horizontalAxisDirection
      ..verticalOffset = verticalOffset
      ..verticalAxisDirection = verticalAxisDirection
      ..mainAxis = mainAxis
      ..delegate = delegate
      ..cacheExtent = cacheExtent
      ..clipBehavior = clipBehavior;
  }
}

class RenderTwoDimensionalGridViewport extends RenderTwoDimensionalViewport {
  RenderTwoDimensionalGridViewport({
    required super.horizontalOffset,
    required super.horizontalAxisDirection,
    required super.verticalOffset,
    required super.verticalAxisDirection,
    required TwoDimensionalChildBuilderDelegate delegate,
    required super.mainAxis,
    required super.childManager,
    super.cacheExtent = 10,
    super.clipBehavior = Clip.hardEdge,
  }) : super(delegate: delegate);

  @override
  void layoutChildSequence() {
    final double horizontalPixels = horizontalOffset.pixels;
    final double verticalPixels = verticalOffset.pixels;
    final double viewportWidth = viewportDimension.width + cacheExtent;
    final double viewportHeight = viewportDimension.height + cacheExtent;
    final TwoDimensionalChildBuilderDelegate builderDelegate =
        delegate as TwoDimensionalChildBuilderDelegate;

    final int maxRowIndex = builderDelegate.maxYIndex!;
    final int maxColumnIndex = builderDelegate.maxXIndex!;

    final int leadingColumn = math.max((horizontalPixels / 200).floor(), 0);
    final int leadingRow = math.max((verticalPixels / 200).floor(), 0);
    final int trailingColumn = math.min(
      ((horizontalPixels + viewportWidth) / 200).ceil(),
      maxColumnIndex,
    );
    final int trailingRow = math.min(
      ((verticalPixels + viewportHeight) / 200).ceil(),
      maxRowIndex,
    );

    double xLayoutOffset = (leadingColumn * 200) - horizontalOffset.pixels;
    for (int column = leadingColumn; column <= trailingColumn; column++) {
      double yLayoutOffset = (leadingRow * 200) - verticalOffset.pixels;
      for (int row = leadingRow; row <= trailingRow; row++) {
        final ChildVicinity vicinity =
            ChildVicinity(xIndex: column, yIndex: row);
        final RenderBox? child = buildOrObtainChildFor(vicinity);

        if (child != null) {
          child.layout(constraints.loosen());

          // Subclasses only need to set the normalized layout offset. The super
          // class adjusts for reversed axes.
          parentDataOf(child).layoutOffset =
              Offset(xLayoutOffset, yLayoutOffset);
        }

        yLayoutOffset += 200;
      }
      xLayoutOffset += 200;
    }

    // Set the min and max scroll extents for each axis.
    final double verticalExtent = 200 * (maxRowIndex + 1);
    verticalOffset.applyContentDimensions(
      0.0,
      clampDouble(
          verticalExtent - viewportDimension.height, 0.0, double.infinity),
    );
    final double horizontalExtent = 200 * (maxColumnIndex + 1);
    horizontalOffset.applyContentDimensions(
      0.0,
      clampDouble(
          horizontalExtent - viewportDimension.width, 0.0, double.infinity),
    );
    // Super class handles garbage collection too!
  }
}
flutter doctor -v
[!] Flutter (Channel stable, 3.16.5, on macOS 14.1.2 23B92 darwin-arm64, locale en-GB)
    • Flutter version 3.16.5 on channel stable at /Users/nexus/dev/sdks/flutter
    ! Warning: `flutter` on your path resolves to /Users/nexus/dev/sdks/flutters/bin/flutter, which is not inside your current Flutter SDK checkout at /Users/nexus/dev/sdks/flutter. Consider adding /Users/nexus/dev/sdks/flutter/bin to the front of your path.
    ! Warning: `dart` on your path resolves to /Users/nexus/dev/sdks/flutters/bin/dart, which is not inside your current Flutter SDK checkout at /Users/nexus/dev/sdks/flutter. Consider adding /Users/nexus/dev/sdks/flutter/bin to the front of your path.
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 78666c8dc5 (3 weeks ago), 2023-12-19 16:14:14 -0800
    • Engine revision 3f3e560236
    • Dart version 3.2.3
    • DevTools version 2.28.4
    • If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades.

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0-rc1)
    • Android SDK at /Users/nexus/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0-rc1
    • Java binary at: /Users/nexus/Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.0)
    • Xcode at /Applications/Xcode-15.0.0-Release.Candidate.app/Contents/Developer
    • Build 15A240d
    • CocoaPods version 1.14.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.3)
    • Android Studio at /Users/nexus/Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)

[✓] IntelliJ IDEA Ultimate Edition (version 2023.2.5)
    • IntelliJ at /Users/nexus/Applications/IntelliJ IDEA Ultimate.app
    • Flutter plugin version 76.3.4
    • Dart plugin version 232.10072.19

[✓] VS Code (version 1.85.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.80.0

[✓] Connected device (4 available)
    • Nexus (mobile)       • 00008020-001875E83A38002E • ios            • iOS 17.2.1 21C66
    • Dean’s iPad (mobile) • 00008103-000825C811E3401E • ios            • iOS 17.2 21C62
    • macOS (desktop)      • macos                     • darwin-arm64   • macOS 14.1.2 23B92 darwin-arm64
    • Chrome (web)         • chrome                    • web-javascript • Google Chrome 120.0.6099.199

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 1 category.
[✓] Flutter (Channel master, 3.18.0-19.0.pre.118, on macOS 14.1.2 23B92 darwin-arm64, locale en-GB)
    • Flutter version 3.18.0-19.0.pre.118 on channel master at /Users/nexus/dev/sdks/flutters
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 29db9dbd44 (3 hours ago), 2024-01-08 23:24:31 -0500
    • Engine revision 820645dbcc
    • Dart version 3.4.0 (build 3.4.0-4.0.dev)
    • DevTools version 2.31.0

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0-rc1)
    • Android SDK at /Users/nexus/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0-rc1
    • Java binary at: /Users/nexus/Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.0)
    • Xcode at /Applications/Xcode-15.0.0-Release.Candidate.app/Contents/Developer
    • Build 15A240d
    • CocoaPods version 1.14.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.3)
    • Android Studio at /Users/nexus/Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)

[✓] IntelliJ IDEA Ultimate Edition (version 2023.2.5)
    • IntelliJ at /Users/nexus/Applications/IntelliJ IDEA Ultimate.app
    • Flutter plugin version 76.3.4
    • Dart plugin version 232.10072.19

[✓] VS Code (version 1.85.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.80.0

[✓] Connected device (4 available)
    • Nexus (mobile)       • 00008020-001875E83A38002E • ios            • iOS 17.2.1 21C66
    • Dean’s iPad (mobile) • 00008103-000825C811E3401E • ios            • iOS 17.2 21C62
    • macOS (desktop)      • macos                     • darwin-arm64   • macOS 14.1.2 23B92 darwin-arm64
    • Chrome (web)         • chrome                    • web-javascript • Google Chrome 120.0.6099.199

[✓] Network resources
    • All expected network resources are available.

• No issues found!

danagbemava-nc avatar Jan 09 '24 07:01 danagbemava-nc

Doing some investigation, I found that the root of this issue is the way _moveChild implemented. _moveChild assigns the child in _children map from "old key" to "new key" causing the child occupying the "new key" being removed from _children, and therefore future calls to get that forgotten child's parentData will fail due to an assertion in parentDataOf. I think the assertion in parentDataOf is unnecessary and it can be removed. WDYT? @Piinks @danagbemava-nc

https://github.com/flutter/flutter/blob/5f17badf4118b474f0b97ee1afe0773ac92b1e4b/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart#L1629-L1638

https://github.com/flutter/flutter/blob/5f17badf4118b474f0b97ee1afe0773ac92b1e4b/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart#L782-L785

Amir-P avatar Jan 09 '24 10:01 Amir-P

Thanks for looking into this. I think the assertion should stay but also maybe it should include those that are being kept alive, and those that are currently in the orphan list?

I wonder if this is something that would be fixed by https://github.com/flutter/flutter/issues/130754 One dimensional scrolling supports this with the findChildIndexCallback for when children have been reordered.

Piinks avatar Jan 10 '24 21:01 Piinks

Thanks for looking into this. I think the assertion should stay but also maybe it should include those that are being kept alive, and those that are currently in the orphan list?

I wonder if this is something that would be fixed by #130754 One dimensional scrolling supports this with the findChildIndexCallback for when children have been reordered.

According to my tests 2D foundation is working fine for reordering and the only problem is with the assertion in parentDataOf which can be fixed by including checks for debug orphans and keepAlive bucket. I will open a PR in a few minutes. @Piinks

Amir-P avatar Jan 13 '24 07:01 Amir-P

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

github-actions[bot] avatar Feb 12 '24 07:02 github-actions[bot]