Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with rendering a CustomBoxy when a new item is added to an animated list #20

Closed
Taco55 opened this issue Mar 25, 2023 · 3 comments
Labels
bug Something isn't working

Comments

@Taco55
Copy link

Taco55 commented Mar 25, 2023

Boxy is a great library and makes a layout possible that I could not achieve with just normal Rows and Columns. However, I encounter a problem when I add an item to an animated list (of an external library), while the initial rendering of the list does not give any problems. Hopefully some help is possible.

I get the following error after adding a new item to a list:

════════ Exception caught by rendering library ═════════════════════════════════
The following assertion was thrown during performLayout():
'package:flutter/src/rendering/object.dart': Failed assertion: line 1048 pos 12: '_debugDoingLayout': is not true.

The relevant error-causing widget was
_CustomBoxy
When the exception was thrown, this was the stack
#2      PipelineOwner._enableMutationsToDirtySubtrees
#3      RenderObject.invokeLayoutCallback
#4      InflatingRenderObjectMixin._allowSubtreeMutation
#5      InflatingRenderObjectMixin.flushInflateQueue
#6      InflatingRenderObjectMixin.performLayout.<anonymous closure>
#7      InflatingElement._wrapInflater
#8      InflatingRenderObjectMixin.performLayout
#9      RenderBoxyMixin.performLayout
#10     RenderObject.layout
#11     RenderBox.layout
#12     RenderProxyBoxMixin.performLayout
#13     RenderObject.layout
#14     RenderBox.layout
#15     RenderProxyBoxMixin.performLayout
#16     RenderObject.layout
#17     RenderBox.layout
#18     RenderProxyBoxMixin.performLayout
#19     RenderCustomPaint.performLayout
#20     RenderObject.layout
#21     RenderBox.layout
#22     RenderProxyBoxMixin.performLayout
#23     _RenderCustomClip.performLayout
#24     RenderObject.layout
#25     RenderBox.layout
#26     RenderPadding.performLayout
#27     RenderObject.layout
#28     RenderBox.layout
#29     RenderProxyBoxMixin.performLayout
#30     RenderObject.layout
#31     RenderBox.layout
#32     AnimatedRenderSliverList.measureItem.<anonymous closure>
#33     AnimatedSliverMultiBoxAdaptorElement.disposableElement.<anonymous closure>
#34     BuildOwner.lockState
#35     AnimatedSliverMultiBoxAdaptorElement.disposableElement
#36     AnimatedRenderSliverList.measureItem
#37     AnimatedRenderSliverList.measureItems.<anonymous closure>
#42     _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:192:26)
(elided 6 frames from class _AssertionError, class _Timer, dart:async, and dart:async-patch)
The following RenderObject was being processed when the exception was fired: RenderBoxy<BoxyChild>#ae96a relayoutBoundary=up8 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
RenderObject: RenderBoxy<BoxyChild>#ae96a relayoutBoundary=up8 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
    parentData: <none> (can use size)
    constraints: BoxConstraints(w=377.0, 0.0<=h<=Infinity)
    size: Size(377.0, 40.0)
    child 1: RenderPadding#43672 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
        parentData: offset=Offset(0.0, 0.0) (can use size)
        constraints: BoxConstraints(w=40.0, h=40.0)
        size: Size(40.0, 40.0)
        padding: EdgeInsets.all(8.0)
        textDirection: ltr
        child: RenderSemanticsAnnotations#f1bca NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
            parentData: offset=Offset(8.0, 8.0) (can use size)
            constraints: BoxConstraints(w=24.0, h=24.0)
            size: Size(24.0, 24.0)
            child: RenderExcludeSemantics#21afb NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
                parentData: <none> (can use size)
                constraints: BoxConstraints(w=24.0, h=24.0)
                size: Size(24.0, 24.0)
                excluding: true
                child: RenderConstrainedBox#e852e NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
                    parentData: <none> (can use size)
                    constraints: BoxConstraints(w=24.0, h=24.0)
                    size: Size(24.0, 24.0)
                    additionalConstraints: BoxConstraints(w=24.0, h=24.0)
    child 2: RenderPositionedBox#c6b42 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
        parentData: offset=Offset(0.0, 0.0) (can use size)
        constraints: BoxConstraints(w=49.0, h=40.0)
        size: Size(49.0, 40.0)
        alignment: Alignment.center
        textDirection: ltr
        widthFactor: expand
        heightFactor: expand
        child: RenderParagraph#89c15 relayoutBoundary=up1 NEEDS-PAINT
            parentData: offset=Offset(0.0, 11.5) (can use size)
            constraints: BoxConstraints(0.0<=w<=49.0, 0.0<=h<=40.0)
            size: Size(49.0, 17.0)
            textAlign: start
            textDirection: ltr
            softWrap: wrapping at box width
            overflow: clip
            locale: en_US
            maxLines: unlimited
            text: TextSpan
                debugLabel: (englishLike bodyMedium 2014).merge(blackCupertino bodyMedium)
                inherit: false
                color: Color(0xdd000000)
                family: .SF UI Text
                size: 14.0
                weight: 400
                baseline: alphabetic
                decoration: TextDecoration.none
                "index 4"
════════════════════════════════════════════════════════════════════════════════

The (simplified) item tiles are created as follows:

  Widget itemTile(int index) {
    return Card(
      margin: const EdgeInsets.all(8),
      child: CustomBoxy(delegate: TileBoxy(widgetSpacing: 10), children: [
        const Icon(Icons.note),
        Center(child: Text("index $index"))
      ]),
    );
  }
}

With the (simplified) delegate defined as:

class TileBoxy extends BoxyDelegate {
  final double widgetSpacing;

  TileBoxy({this.widgetSpacing = 10});

  @override
  Size layout() {
    List<double> childrenWidths = [];
    for (final child in children) {
      childrenWidths.add(min(constraints.maxWidth,
          child.render.getMaxIntrinsicWidth(double.infinity)));
    }
    var totalChildrenWidth = childrenWidths.reduce((a, b) => a + b);

    var childHeight = 0.0;
    for (var i = 0; i < children.length; i++) {
      childHeight = max(
        childHeight,
        children[i].render.getMinIntrinsicHeight(childrenWidths[i]),
      );
    }

    for (var i = 0; i < children.length; i++) {
      children[i]
          .layout(BoxConstraints.tight(Size(childrenWidths[i], childHeight)));
    }

    var x = 0.0;
    for (var i = 0; i < children.length; i++) {
      children[i].position(Offset(x, 0));
      x += childrenWidths[i] + widgetSpacing;
    }

    return Size(min(totalChildrenWidth, constraints.maxWidth), childHeight);
  }
}

Possibly this problem might be caused by the external library for the animated list (great_list_view). However, the error only occurs when I use CustomBoxy and does not occur when using a standard Row.

Is there something I need to add in the BoxyDelegate to get rid of this error?

@pingbird
Copy link
Owner

I've reproduced the error and suspect great_list_view is doing something fishy that prevents the invokeLayoutCallback from working. This can (probably) be mitigated on the Boxy side because invokeLayoutCallback is technically unnecessary when the BoxyDelegate doesn't call inflate.

@pingbird
Copy link
Owner

pingbird commented Mar 25, 2023

Published 2.0.9 which should mitigate the issue, let me know if that worked for you!

Using BoxyDelegate.inflate or LayoutBuilder will still crash due to the issue mentioned above, but the sample you sent doesn't use either so that shouldn't matter.

@Taco55
Copy link
Author

Taco55 commented Mar 26, 2023

That's so great. Works perfect. Thanks for the great support!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants