Skip to content

Dynamically generated pie chart with badges causes render exception.Β #2029

@zhaozhixu

Description

@zhaozhixu

Describe the bug
A dynamically generated pie chart with badges causes RangeError (length): Invalid value exception.

To Reproduce
Build a simple counter app with a PieChart widget which adds sections when clicking the counter button (counting from 1), and the exception shows in the console log.

import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.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),
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 1;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Expanded(
              child: LayoutBuilder(
                builder: (context, constraints) {
                  return PieChart(
                    PieChartData(
                      sections: _buildChartSections(context, constraints),
                      sectionsSpace: 2,
                      centerSpaceRadius: 0,
                      pieTouchData: PieTouchData(touchCallback: (FlTouchEvent event, pieTouchResponse) {}),
                    ),
                  );
                },
              ),
            ),
            const Text('You have pushed the button this many times:'),
            Text('$_counter', style: Theme.of(context).textTheme.headlineMedium),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }

  List<PieChartSectionData> _buildChartSections(BuildContext context, BoxConstraints constraints) {
    double radius = constraints.maxHeight > constraints.maxWidth ? constraints.maxWidth : constraints.maxHeight;
    print("_buildChartSections: $_counter");

    return List.generate(_counter, (index) {
      final color = Color((DateTime.now().microsecondsSinceEpoch % 0xFFFFFF) | 0xFF000000);
      return PieChartSectionData(
        title: "$index",
        titleStyle: TextStyle(
          fontWeight: FontWeight.bold,
          color: const Color(0xffffffff),
        ),
        value: 10,
        color: color,
        radius: radius * 0.3,
        showTitle: true,
        badgeWidget: _BadgeWidget("$index", color, radius * 0.1),
        badgePositionPercentageOffset: .98,
      );
    });
  }
}

class _BadgeWidget extends StatelessWidget {
  final String txt;
  final Color color;
  final double radius;

  const _BadgeWidget(this.txt, this.color, this.radius);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: radius,
      decoration: BoxDecoration(
        color: Theme.of(context).colorScheme.surface,
        shape: BoxShape.circle,
        border: Border.all(color: color, width: 2),
      ),
      child: Center(
        child: Text(txt, style: TextStyle(color: color)),
      ),
    );
  }
}

Console output

Launching lib/main.dart on sdk gphone64 arm64 in debug mode...
Running Gradle task 'assembleDebug'...                              3.7s
βœ“ Built build/app/outputs/flutter-apk/app-debug.apk
Installing build/app/outputs/flutter-apk/app-debug.apk...          466ms
D/FlutterJNI(19685): Beginning load of flutter...
D/FlutterJNI(19685): flutter (null) was loaded normally!
I/flutter (19685): [IMPORTANT:flutter/shell/platform/android/android_context_gl_impeller.cc(104)] Using the Impeller rendering backend (OpenGLES).
Syncing files to device sdk gphone64 arm64...                       21ms

Flutter run key commands.
r Hot reload. πŸ”₯πŸ”₯πŸ”₯
R Hot restart.
h List all available interactive commands.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).

A Dart VM Service on sdk gphone64 arm64 is available at: http://127.0.0.1:53282/6UBWvL27vP8=/
I/flutter (19685): _buildChartSections: 1
The Flutter DevTools debugger and profiler on sdk gphone64 arm64 is available at: http://127.0.0.1:9101?uri=http://127.0.0.1:53282/6UBWvL27vP8=/
I/WindowExtensionsImpl(19685): Initializing Window Extensions, vendor API level=6, activity embedding enabled=true
W/HWUI    (19685): Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
W/HWUI    (19685): Failed to initialize 101010-2 format, error = EGL_SUCCESS
I/Gralloc4(19685): mapper 4.x is not supported
I/flutter (19685): _buildChartSections: 1
I/.test_pie_chart(19685): Compiler allocated 5250KB to compile void android.view.ViewRootImpl.performTraversals()
I/flutter (19685): _buildChartSections: 2

══║ EXCEPTION CAUGHT BY RENDERING LIBRARY β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
The following RangeError was thrown during paint():
RangeError (length): Invalid value: Only valid value is 0: 1

The relevant error-causing widget was:
  PieChartLeaf
  PieChartLeaf:file:///Users/zhixu/.pub-cache/hosted/pub.dev/fl_chart-1.1.1/lib/src/chart/pie_chart/pie_chart.dart:57:12

When the exception was thrown, this was the stack:
#0      List.[] (dart:core-patch/growable_array.dart)
#1      RenderPieChart.badgeWidgetPaint (package:fl_chart/src/chart/pie_chart/pie_chart_renderer.dart:154:24)
#2      RenderPieChart.paint (package:fl_chart/src/chart/pie_chart/pie_chart_renderer.dart:146:5)
#3      RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3423:7)
#4      PaintingContext.paintChild (package:flutter/src/rendering/object.dart:261:13)
#5      _RenderLayoutBuilder.paint (package:flutter/src/widgets/layout_builder.dart:471:15)
#6      RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3423:7)
#7      PaintingContext.paintChild (package:flutter/src/rendering/object.dart:261:13)
#8      RenderBoxContainerDefaultsMixin.defaultPaint (package:flutter/src/rendering/box.dart:3367:15)
#9      RenderFlex.paint (package:flutter/src/rendering/flex.dart:1317:7)
#10     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3423:7)
#11     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:261:13)
#12     RenderShiftedBox.paint (package:flutter/src/rendering/shifted_box.dart:81:15)
#13     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3423:7)
#14     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:261:13)
#15     RenderBoxContainerDefaultsMixin.defaultPaint (package:flutter/src/rendering/box.dart:3367:15)
#16     RenderCustomMultiChildLayoutBox.paint (package:flutter/src/rendering/custom_layout.dart:425:5)
#17     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3423:7)
#18     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:261:13)
#19     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:13)
#20     _RenderInkFeatures.paint (package:flutter/src/material/material.dart:634:11)
#21     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3423:7)
#22     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:261:13)
#23     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:13)
#24     RenderPhysicalModel.paint.<anonymous closure> (package:flutter/src/rendering/proxy_box.dart:2184:15)
#25     PaintingContext.pushClipRRect (package:flutter/src/rendering/object.dart:609:14)
#26     RenderPhysicalModel.paint (package:flutter/src/rendering/proxy_box.dart:2171:21)
#27     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3423:7)
#28     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:261:13)
#29     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:13)
#30     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3423:7)
#31     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:261:13)
#32     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:13)
#33     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3423:7)
#34     PaintingContext._repaintCompositedChild (package:flutter/src/rendering/object.dart:176:11)
#35     PaintingContext.repaintCompositedChild (package:flutter/src/rendering/object.dart:121:5)
#36     PipelineOwner.flushPaint (package:flutter/src/rendering/object.dart:1309:31)
#37     PipelineOwner.flushPaint (package:flutter/src/rendering/object.dart:1319:15)
#38     RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:631:23)
#39     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1261:13)
#40     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5)
#41     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15)
#42     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9)
#43     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5)
#44     _invoke (dart:ui/hooks.dart:330:13)
#45     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5)
#46     _drawFrame (dart:ui/hooks.dart:302:31)

The following RenderObject was being processed when the exception was fired: RenderPieChart#2195c relayoutBoundary=up4:
  creator: PieChartLeaf ← PieChart ← LayoutBuilder ← Expanded ← Column ← Center ←
    KeyedSubtree-[GlobalKey#82df0] ← _BodyBuilder ← MediaQuery ← LayoutId-[<_ScaffoldSlot.body>] ←
    CustomMultiChildLayout ← _ActionsScope ← β‹―
  parentData: offset=Offset(0.0, 0.0) (can use size)
  constraints: BoxConstraints(0.0<=w<=411.4, h=778.3)
  size: Size(411.4, 778.3)
This RenderObject had the following descendants (showing up to depth 5):
    child 1: RenderConstrainedBox#d4bfa relayoutBoundary=up5
      child: RenderDecoratedBox#933ec relayoutBoundary=up6
        child: RenderPadding#c000a relayoutBoundary=up7
          child: RenderPositionedBox#6aba5 relayoutBoundary=up8
            child: RenderParagraph#e98c4 relayoutBoundary=up9
    child 2: RenderConstrainedBox#d06a6 NEEDS-LAYOUT NEEDS-PAINT
      child: RenderDecoratedBox#0e69a NEEDS-LAYOUT NEEDS-PAINT
        child: RenderPadding#f2c2f NEEDS-LAYOUT NEEDS-PAINT
          child: RenderPositionedBox#d83d8 NEEDS-LAYOUT NEEDS-PAINT
            child: RenderParagraph#27aa9 NEEDS-LAYOUT NEEDS-PAINT
════════════════════════════════════════════════════════════════════════════════════════════════════

Versions

  • which version of the Flutter are you using? 3.35.7
  • which version of the FlChart are you using? 1.1.1

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