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

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

Open
absar opened this issue Sep 30, 2024 · 1 comment

Comments

@absar
Copy link

absar commented Sep 30, 2024

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)
@OutdatedGuy
Copy link

OutdatedGuy commented Dec 3, 2024

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
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants