7

I'm trying to get a chart from the charts_flutter package to expand to fill available space, when it is inside a Row which is inside a Column. I've spent a couple of hours trying to do this but I must be missing something! This is visually what I'm trying to achieve:

enter image description here

Here's a minimal working example. I must have tried a hundred combinations of Expanded, Flexible, main axis size, cross axis alignment etc. but I just can't seem to find the correct one. Currently the bottom overflows by infinity pixels, with object was given an infinite size during layout. There is this open issue, I don't know if it's related, and there is no answer. I just need help with the bit of code inside runApp:

import 'package:charts_flutter/flutter.dart' as charts;
import 'package:flutter/material.dart';

void main() => runApp(

  // HOW DO I LAY THIS OUT?
  Column(
    children: <Widget>[
      Container(height: 200, color: Colors.orange),
      Row(
        textDirection: TextDirection.ltr,
        children: <Widget>[
          Container(width: 200,color: Colors.orange),
          Expanded(child: SimpleTimeSeriesChart.withSampleData())
        ],
      )
    ],
  )
);

class SimpleTimeSeriesChart extends StatelessWidget {
  final List<charts.Series> seriesList;
  final bool animate;

  SimpleTimeSeriesChart(this.seriesList, {this.animate});

  factory SimpleTimeSeriesChart.withSampleData() {
    return new SimpleTimeSeriesChart(
      _createSampleData(),
      animate: false,
    );
  }

  @override
  Widget build(BuildContext context) {
    return new charts.TimeSeriesChart(
      seriesList,
      animate: animate,
      dateTimeFactory: const charts.LocalDateTimeFactory(),
    );
  }

  /// Create one series with sample hard coded data.
  static List<charts.Series<TimeSeriesSales, DateTime>> _createSampleData() {
    final data = [
      new TimeSeriesSales(new DateTime(2017, 9, 19), 5),
      new TimeSeriesSales(new DateTime(2017, 9, 26), 25),
      new TimeSeriesSales(new DateTime(2017, 10, 3), 100),
      new TimeSeriesSales(new DateTime(2017, 10, 10), 75),
    ];

    return [
      new charts.Series<TimeSeriesSales, DateTime>(
        id: 'Sales',
        colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
        domainFn: (TimeSeriesSales sales, _) => sales.time,
        measureFn: (TimeSeriesSales sales, _) => sales.sales,
        data: data,
      )
    ];
  }
}

class TimeSeriesSales {
  final DateTime time;
  final int sales;

  TimeSeriesSales(this.time, this.sales);
}
James Allen
  • 6,406
  • 8
  • 50
  • 83

2 Answers2

16

**see why at Step 8 - scroll down **

Problem

I'm trying to get a chart from the charts_flutter package to expand to fill available space

Error Evidence

object was given an infinite size during layout

Solution

Wrap the Row with Expanded

Column(children: <Widget>[Expanded(child: Row())])

Screenshot

enter image description here

Note:

  • , thanks for provide minimal code

Full Working Code

import 'package:charts_flutter/flutter.dart' as charts;
import 'package:flutter/material.dart';

void main() => runApp(

        // HOW DO I LAY THIS OUT?
        Column(
      children: <Widget>[
        Container(height: 200, color: Colors.orange),
        Expanded(
          child: Row(
            textDirection: TextDirection.ltr,
            children: <Widget>[
              Container(width: 200, color: Colors.green),
              Expanded(child: SimpleTimeSeriesChart.withSampleData()),
            ],
          ),
        )
      ],
    ));

class SimpleTimeSeriesChart extends StatelessWidget {
  final List<charts.Series> seriesList;
  final bool animate;

  SimpleTimeSeriesChart(this.seriesList, {this.animate});

  factory SimpleTimeSeriesChart.withSampleData() {
    return new SimpleTimeSeriesChart(
      _createSampleData(),
      animate: false,
    );
  }

  @override
  Widget build(BuildContext context) {
    return new charts.TimeSeriesChart(
      seriesList,
      animate: animate,
      dateTimeFactory: const charts.LocalDateTimeFactory(),
    );
  }

  /// Create one series with sample hard coded data.
  static List<charts.Series<TimeSeriesSales, DateTime>> _createSampleData() {
    final data = [
      new TimeSeriesSales(new DateTime(2017, 9, 19), 5),
      new TimeSeriesSales(new DateTime(2017, 9, 26), 25),
      new TimeSeriesSales(new DateTime(2017, 10, 3), 100),
      new TimeSeriesSales(new DateTime(2017, 10, 10), 75),
    ];

    return [
      new charts.Series<TimeSeriesSales, DateTime>(
        id: 'Sales',
        colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
        domainFn: (TimeSeriesSales sales, _) => sales.time,
        measureFn: (TimeSeriesSales sales, _) => sales.sales,
        data: data,
      )
    ];
  }
}

class TimeSeriesSales {
  final DateTime time;
  final int sales;

  TimeSeriesSales(this.time, this.sales);
}

Extra : how to read the error (Full Error Dump Attached in the end)

Step 1 : Locate the start

I/flutter ( 4228): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════

Step 2: Locate the end

I/flutter ( 4228): ════════════════════════════════════════════════════════════════════════════════════════════════════

Step 3: read the error

scan the error with your eyes you will see some phrases like


I/flutter ( 4228):     constraints: BoxConstraints(w=320.0, h=480.0)

I/flutter ( 4228): The following assertion was thrown during performLayout():

I/flutter ( 4228): Summary 1: RenderCustomMultiChildLayoutBox object was given an infinite size during layout.

Step 4 :decide what is the type of the

this is a box constraints error

Step 5 :how to know what widget is throwing the error

go near the end it will give you the source:

I/flutter ( 4228):   creator: CustomMultiChildLayout ← TimeSeriesChart ← SimpleTimeSeriesChart ← Expanded ← Row ← Column
I/flutter ( 4228):     ← [root]
  • so it is inside the TimeSeriesChart

Step 6 : what is missing

go near the end it will give you the missing constraint

I/flutter ( 4228):   constraints: BoxConstraints(w=120.0, 0.0<=h<=Infinity)
  • notice : 0.0<=h<=Infinity

  • the height can't be Infinity

Step 7 :

  • warp the source with a SizedBox to make sure it' what throwing the error , to see if it solve it

  • SizedBox

    A box with a specified size.

    If given a child, this widget forces its child to have a specific width and/or height (assuming values are permitted by this widget's parent). If either the width or height is null, this widget will size itself to match the child's size in that dimension.

Step 8 :

  1. the TimeSeriesChart(child) asked Raw(parent) for height

  2. the Raw(child) asked Column(parent) for height

  3. the Column doesn't know

  4. by why the Column doesn't know, because by default behavior is that it will leave it for the children to decide thir own height

  5. but we can tell the Column that the children doesn't know so expand them to the available space

Error Dump

I/flutter ( 4228): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter ( 4228): The following assertion was thrown during performLayout():
I/flutter ( 4228): FlutterError contained multiple error summaries.
I/flutter ( 4228): All FlutterError objects should have only a single short (one line) summary description of the
I/flutter ( 4228): problem that was detected.
I/flutter ( 4228): Malformed FlutterError:
I/flutter ( 4228):   RenderCustomMultiChildLayoutBox object was given an infinite size during layout.
I/flutter ( 4228):   This probably means that it is a render object that tries to be as big as possible, but it was put
I/flutter ( 4228):   inside another render object that allows its children to pick their own size.
I/flutter ( 4228):   RenderCustomMultiChildLayoutBox object was given an infinite size during layout.
I/flutter ( 4228):   This probably means that it is a render object that tries to be as big as possible, but it was put
I/flutter ( 4228):   inside another render object that allows its children to pick their own size.
I/flutter ( 4228):   The nearest ancestor providing an unbounded height constraint is: RenderFlex#d29e7 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE:
I/flutter ( 4228):     creator: Column ← [root]
I/flutter ( 4228):     parentData: <none>
I/flutter ( 4228):     constraints: BoxConstraints(w=320.0, h=480.0)
I/flutter ( 4228):     size: MISSING
I/flutter ( 4228):     direction: vertical
I/flutter ( 4228):     mainAxisAlignment: start
I/flutter ( 4228):     mainAxisSize: max
I/flutter ( 4228):     crossAxisAlignment: center
I/flutter ( 4228):     verticalDirection: down
I/flutter ( 4228):   The constraints that applied to the RenderCustomMultiChildLayoutBox were:
I/flutter ( 4228):     BoxConstraints(w=120.0, 0.0<=h<=Infinity)
I/flutter ( 4228):   The exact size it was given was:
I/flutter ( 4228):     Size(120.0, Infinity)
I/flutter ( 4228):   See https://flutter.dev/docs/development/ui/layout/box-constraints for more information.
I/flutter ( 4228):
I/flutter ( 4228): The malformed error has 2 summaries.
I/flutter ( 4228): Summary 1: RenderCustomMultiChildLayoutBox object was given an infinite size during layout.
I/flutter ( 4228): Summary 2: RenderCustomMultiChildLayoutBox object was given an infinite size during layout.
I/flutter ( 4228):
I/flutter ( 4228): This error should still help you solve your problem, however please also report this malformed error
I/flutter ( 4228): in the framework by filing a bug on GitHub:
I/flutter ( 4228):   https://github.com/flutter/flutter/issues/new?template=BUG.md
I/flutter ( 4228):
I/flutter ( 4228): When the exception was thrown, this was the stack:
I/flutter ( 4228): #0      new FlutterError.fromParts.<anonymous closure> (package:flutter/src/foundation/assertions.dart:540:9)
I/flutter ( 4228): #1      new FlutterError.fromParts (package:flutter/src/foundation/assertions.dart:543:6)
I/flutter ( 4228): #2      RenderBox.debugAssertDoesMeetConstraints.<anonymous closure> (package:flutter/src/rendering/box.dart:1966:28)
I/flutter ( 4228): #3      RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2029:6)
I/flutter ( 4228): #4      RenderBox.size=.<anonymous closure> (package:flutter/src/rendering/box.dart:1740:7)
I/flutter ( 4228): #5      RenderBox.size= (package:flutter/src/rendering/box.dart:1742:6)
I/flutter ( 4228): #6      RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:355:5)
I/flutter ( 4228): #7      RenderObject.layout (package:flutter/src/rendering/object.dart:1619:7)
I/flutter ( 4228): #8      RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:805:17)
I/flutter ( 4228): #9      RenderObject.layout (package:flutter/src/rendering/object.dart:1619:7)
I/flutter ( 4228): #10     RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:743:15)
I/flutter ( 4228): #11     RenderObject.layout (package:flutter/src/rendering/object.dart:1619:7)
I/flutter ( 4228): #12     RenderView.performLayout (package:flutter/src/rendering/view.dart:151:13)
I/flutter ( 4228): #13     RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:1496:7)
I/flutter ( 4228): #14     PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:765:18)
I/flutter ( 4228): #15     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:346:19)
I/flutter ( 4228): #16     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:701:13)
I/flutter ( 4228): #17     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:285:5)I/flutter ( 4228): #18     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1016:15)
I/flutter ( 4228): #19     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:958:9)
I/flutter ( 4228): #20     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:784:7)
I/flutter ( 4228): #29     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:382:19)
I/flutter ( 4228): #30     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:416:5)
I/flutter ( 4228): #31     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:172:12)
I/flutter ( 4228): (elided 8 frames from package dart:async and package dart:async-patch)
I/flutter ( 4228):
I/flutter ( 4228): The following RenderObject was being processed when the exception was fired: RenderCustomMultiChildLayoutBox#e4ae0 relayoutBoundary=up2 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE:
I/flutter ( 4228):   creator: CustomMultiChildLayout ← TimeSeriesChart ← SimpleTimeSeriesChart ← Expanded ← Row ← Column
I/flutter ( 4228):     ← [root]
I/flutter ( 4228):   parentData: offset=Offset(0.0, 0.0); flex=1; fit=FlexFit.tight (can use size)
I/flutter ( 4228):   constraints: BoxConstraints(w=120.0, 0.0<=h<=Infinity)
I/flutter ( 4228):   size: Size(120.0, Infinity)
I/flutter ( 4228): This RenderObject had the following descendants (showing up to depth 5):
I/flutter ( 4228):     child 1: RenderSemanticsGestureHandler#2034c NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I/flutter ( 4228):       child: RenderPointerListener#aef29 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I/flutter ( 4228):         child: ChartContainerRenderObject<DateTime>#b28fc NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 4228): ════════════════════════════════════════════════════════════════════════════════════════════════════

more on step 8

  • now we know that the error is from the TimeSeriesChart widget because it needs height
  • but if it does not have a height it will ask it's parent, the row

  • but the row dosnt have a fixed height it will ask the children

  • but the children don't have a fixed height it will ask the row parent

  • but the parent doesn't have a fixed height for it children (the row)

James Allen
  • 6,406
  • 8
  • 50
  • 83
Mohamed Elrashid
  • 8,125
  • 6
  • 31
  • 46
  • Super comprehensive answer, thanks! Miguel was first though so he gets the bounty – James Allen Aug 30 '19 at 13:46
  • @JamesAllen my answer is at ***2019-08-28 17:16:56Z*** Miguel was at ***2019-08-28 17:33:09Z*** my answer was 15 mint before him ,with ❤ check [How do I tell exactly what time an answer was posted? - Meta Stack Exchange](https://meta.stackexchange.com/questions/119627/how-do-i-tell-exactly-what-time-an-answer-was-posted) – Mohamed Elrashid Aug 30 '19 at 21:55
  • Oh damn you're right, sorry Mohamed - that's so weird, I'm sure I saw Miguel's answer first. I can't see any way to change the bounty. Sorry dude my bad – James Allen Sep 11 '19 at 00:01
5

Just wrap your Row in an Expanded widget and that's it.

 Column(
    children: <Widget>[
      Container(height: 200, color: Colors.orange),
      Expanded(
        child: Row(
        textDirection: TextDirection.ltr,
        children: <Widget>[
          Container(width: 200,color: Colors.orange),
          Expanded(child: SimpleTimeSeriesChart.withSampleData())
        ],
      )
     )
    ],
  )

Explanation is that the Column when created will provide infinity constraints to its children and when you wrap any child in a Flexible widget, it will act accordingly to the available space (and some of the properties, if any).

The Row acts exactly the same way, but horizontally. Here, you are properly adding the Expanded to the Row child, but then, it tries to find how much cant it expand to size itself, and the Row doesn't know because it still has an unbounded height from the parent (Column), that's why you should use the Expanded or even a Flexible if you don't need to fit the available space.

Miguel Ruivo
  • 16,035
  • 7
  • 57
  • 87
  • 1
    Thanks - for some reason I never even thought of wrapping the row in an expanded! You get the bounty for being first with the correct answer, but Mohamed's answer is accepted because it's also correct but more comprehensive – James Allen Aug 30 '19 at 13:45