Skip to content

LayoutBuilder does not support returning intrinsic dimensions, started in v0.8.0 #99

Open

Description

@absar

The following error started after upgrading to v0.8.0

Code sample
import 'package:flutter/material.dart';
import 'package:confetti/confetti.dart';

void main() {
  runApp(
    MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Layout builder issue in v0.8')),
        body: const ConfettiLayoutBuilderIssue(),
      ),
    ),
  );
}

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

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          FilledButton.tonal(
            onPressed: () => showDialog(
              context: context,
              builder: (_) =>
                  const AlertDialog(title: BalanceWidget(message: 'Tap to change value')),
            ),
            child: const Text('Tap to open dialog with confetti, I crash'),
          ),
          const SizedBox(height: 20),
          const BalanceWidget(message: 'Tap to change value, I do not crash'),
        ],
      ),
    );
  }
}

class BalanceWidget extends StatefulWidget {
  const BalanceWidget({super.key, required this.message});

  final String message;

  @override
  State<BalanceWidget> createState() => _BalanceWidgetState();
}

class _BalanceWidgetState extends State<BalanceWidget> {
  double _balance = 20.0;

  @override
  Widget build(BuildContext context) {
    return Stack(
      alignment: Alignment.center,
      children: [
        FilledButton.tonal(
          onPressed: () {
            _balance += 15;
            setState(() {});
          },
          child: Text('${widget.message} ${_balance.toString()}'),
        ),
        _Confetti(value: _balance),
      ],
    );
  }
}

class _Confetti extends StatefulWidget {
  const _Confetti({this.value});

  final double? value;

  @override
  State<_Confetti> createState() => _ConfettiState();
}

class _ConfettiState extends State<_Confetti> {
  late ConfettiController _confettiController;

  double? get value => widget.value;

  @override
  void initState() {
    super.initState();
    _confettiController = ConfettiController(duration: const Duration(seconds: 1));
  }

  @override
  void dispose() {
    _confettiController.dispose();
    super.dispose();
  }

  @override
  void didUpdateWidget(_Confetti oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.value != widget.value && oldWidget.value != null && widget.value != null) {
      _confettiController.play();
    }
  }

  @override
  Widget build(BuildContext context) {
    return ConfettiWidget(
      confettiController: _confettiController,
      blastDirectionality: BlastDirectionality.explosive,
      shouldLoop: false,
    );
  }
}

Error

The following assertion was thrown during performLayout():
LayoutBuilder does not support returning intrinsic dimensions.

Calculating the intrinsic dimensions would require running the layout callback speculatively, which might mutate the live render object tree.
The relevant error-causing widget was:  AlertDialog AlertDialog:/confetti/confetti_layout_builder_issue.dart:29:25
When the exception was thrown, this was the stack: 
#0      _RenderLayoutBuilder._debugThrowIfNotCheckingIntrinsics.<anonymous closure> (package:flutter/src/widgets/layout_builder.dart:399:9)
#1      _RenderLayoutBuilder._debugThrowIfNotCheckingIntrinsics (package:flutter/src/widgets/layout_builder.dart:406:6)
#2      _RenderLayoutBuilder.computeMaxIntrinsicHeight (package:flutter/src/widgets/layout_builder.dart:344:12)
#3      _IntrinsicDimension.memoize.<anonymous closure> (package:flutter/src/rendering/box.dart:1052:49)
#4      _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:543:23)
#5      _IntrinsicDimension.memoize (package:flutter/src/rendering/box.dart:1052:8)
#6      RenderBox._computeWithTimeline (package:flutter/src/rendering/box.dart:1549:32)
#7      RenderBox._computeIntrinsics (package:flutter/src/rendering/box.dart:1527:26)

Activity

  1. OutdatedGuy commented on Dec 3, 2024

    @OutdatedGuy

    Looks like it's related to this flutter/flutter#46063

    @override
    Widget build(BuildContext context) {
    return LayoutBuilder(
    builder: (BuildContext context, BoxConstraints constraints) {
    // Update position and size only when layout changes
    WidgetsBinding.instance.addPostFrameCallback((_) {
    _updatePositionAndSize();
    });
    return RepaintBoundary(
    child: CustomPaint(
    key: _particleSystemKey,
    willChange: true,
    foregroundPainter: ParticlePainter(
    _animController,
    strokeWidth: widget.strokeWidth,
    strokeColor: widget.strokeColor,
    particles: _particleSystem.particles,
    paintEmitterTarget: widget.displayTarget,
    ),
    child: widget.child,
    ),
    );
    },
    );
    }

    @HayesGordon @funwithflutter can you have a look at this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions