diegoveloper / flutter_percent_indicator

Flutter percent indicator library
BSD 2-Clause "Simplified" License
677 stars 206 forks source link

[LinearPercentIndicator] Cannot get size from a render object that has not been through layout in Nested Routes #175

Closed noxasch closed 2 years ago

noxasch commented 2 years ago

Description

I have a nested routes like ''home -> items".

where '/' (home) path contains widget that use percent_indicator.

If I run '/items' directly the stack will be home -> item screen, it will throw the error:

Cannot get size from a render object that has not been through layout.

The size of this render object has not yet been determined because this render object has not yet been through layout, which typically means that the size getter was called too early in the pipeline (e.g., during the build phase) before the framework has determined the size and position of the render objects during layout.

The size getter was called for the following element: CustomPaint-[GlobalKey#753be]
    renderObject: RenderCustomPaint#01d46 NEEDS-LAYOUT NEEDS-PAINT
The render object from which the size was to be obtained was: RenderCustomPaint#01d46 NEEDS-LAYOUT NEEDS-PAINT

When the exception was thrown, this was the stack
#0      Element.size.<anonymous closure>
package:flutter/…/widgets/framework.dart:4141
#1      Element.size
package:flutter/…/widgets/framework.dart:4173
#2      _LinearPercentIndicatorState.initState.<anonymous closure>.<anonymous closure>
package:percent_indicator/linear_percent_indicator.dart:165
#3      State.setState
package:flutter/…/widgets/framework.dart:1109
#4      _LinearPercentIndicatorState.initState.<anonymous closure>
package:percent_indicator/linear_percent_indicator.dart:164
#5      SchedulerBinding._invokeFrameCallback
package:flutter/…/scheduler/binding.dart:1146
#6      SchedulerBinding.handleDrawFrame
package:flutter/…/scheduler/binding.dart:1091
#7      SchedulerBinding.scheduleWarmUpFrame.<anonymous closure>
package:flutter/…/scheduler/binding.dart:864
(elided 11 frames from class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch)

Where the error is thrown:

 WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) {
        setState(() {
          _containerWidth = _containerKey.currentContext?.size?.width ?? 0.0;
          _containerHeight = _containerKey.currentContext?.size?.height ?? 0.0;
          if (_keyIndicator.currentContext != null) {
            _indicatorWidth = _keyIndicator.currentContext?.size?.width ?? 0.0;
            _indicatorHeight =
                _keyIndicator.currentContext?.size?.height ?? 0.0;
          }
        });
      }
    });

Version

percent_indicator: 4.2.2 Flutter SDK: 3.0.5

noxasch commented 2 years ago

closing this as I cannot reproduce bare minimum in flutter.

noxasch commented 2 years ago

If anyone wondering, this is because i have a relatively complex widget tree and haven't been able to reproduce the issue in minimal project. in the meantime I'm using my own for with this fix since it solve my issue:

final RenderBox box =
            _containerKey.currentContext?.findRenderObject() as RenderBox;

        if (box.hasSize) {
          setState(() {
            _containerWidth = _containerKey.currentContext?.size?.width ?? 0.0;
            _containerHeight =
                _containerKey.currentContext?.size?.height ?? 0.0;
            if (_keyIndicator.currentContext != null) {
              _indicatorWidth =
                  _keyIndicator.currentContext?.size?.width ?? 0.0;
              _indicatorHeight =
                  _keyIndicator.currentContext?.size?.height ?? 0.0;
            }
          });
        }
noxasch commented 1 year ago

After investigating, the issue was cause by ListView that contain the LinearPercentIndicator. By setting shrinkWrap: true seems to resolve this issue.