diegoveloper / flutter_percent_indicator

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

Cannot get size in LinearPercentIndicator's initState #174

Open TheVinhLuongFossil opened 2 years ago

TheVinhLuongFossil commented 2 years ago

We are using flutter_percent_indicator version 4.2.2, Flutter SDK version 3.0.5

Here is our exception stack trace:

Non-fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: Null check operator used on a null value. Error thrown Instance of 'ErrorDescription'.
       at RenderBox.size(box.dart:2001)
       at Element.size(framework.dart:4175)
       at _LinearPercentIndicatorState.initState.<fn>.<fn>(linear_percent_indicator.dart:165)
       at State.setState(framework.dart:1109)
       at _LinearPercentIndicatorState.initState.<fn>(linear_percent_indicator.dart:164)
       at SchedulerBinding._invokeFrameCallback(binding.dart:1146)
       at SchedulerBinding.handleDrawFrame(binding.dart:1091)
       at SchedulerBinding._handleDrawFrame(binding.dart:997)

Sadly we cannot reproduce this on our local machine. I think this issue is similar to this so maybe this is a regression bug?

diegoveloper commented 2 years ago

are you sure you are using the latest version? can you check the pubspec.lock file ?

TheVinhLuongFossil commented 2 years ago

@diegoveloper Yes, I checked the pubspec.lock and it is at 4.2.2. Also, in pubspec.yaml we are specifying it as ^4.2.2 so I am certain.

diegoveloper commented 2 years ago

hmm I can't reproduce the issue :/

noxasch commented 2 years ago

maybe related #175 this is cause by complex widget tree which I haven't be able to track the root cause but the patch works for me. I think this is bug in the flutter SDK itself since _containerKey.currentContext?.size?.width should have return null instead of throwing an error. The code in LinerPercentIndicator is correct, but the code doesn't return the expected output which is either null or a double.

mikeesouth commented 1 year ago

I'm also getting this "cannot get size in initState", the stack trace is pretty bad because it comes from Flutter for Web but it's like this:

SingleChildRenderObjectElement.get$size 
_LinearPercentIndicatorState_initState__closure0.call$0 
_LinearPercentIndicatorState.setState$1
_LinearPercentIndicatorState_initState_closure.call$1

I have a table of data and one cell contains a LinearPercentIndicator. I do not get this all the time but it happens within 5 minutes if I filter and sort the data so that the listview have to rebuild the cells containing LinearPercentIndicator. Before it crashes the percent indicator works really nicely but when I filter the list (add/remove items) - sometimes it crashes with this error. I will try to change animate: true to animate: false and see if that helps. I'll also test to set shrinkWrap on the listview according to the comment from @noxasch .

I'm using percent_indicator 4.2.2 and Flutter 3.3.3 (stable).

EDIT: None of the fixes (animate: false or shrinkWrap: true on the listview) helped. Still getting the error. But my use case is very simple (a horizontal linear progress) so I'll just build it myself.

phuppert commented 1 year ago

I'm also experiencing this issue. It's occurring very sporadically, but easily often enough to be noticeable. I couldn't reproduce it with a simple toy example today as it only seems to occur in more complex widget trees. In my case, the LinearPercentIndicator is wrapped in a column together with other, more complex content. Multiple of those columns then make up an animated list view in my app which sometimes, on refresh, will cause this error.

I'll try to produce a minimal (non-)working example by occasion. So far, no changes to the LinearPercentIndicator helped.

diegoveloper commented 1 year ago

yeah please, try to reproduce it in a minimal sample code in order to fix that , thank you

phuppert commented 1 year ago

Try this:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:percent_indicator/linear_percent_indicator.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(AnimatedListExample());
}

class AnimatedListExample extends StatelessWidget {
  AnimatedListExample({
    Key? key,
  }) : super(key: key) {
    // fill list
    () async {
      for (int i = 0; i < 200; i++) {
        await Future.delayed(const Duration(milliseconds: 0));
        _animatedListKey.currentState
            ?.insertItem(0, duration: const Duration(milliseconds: 100));
      }
    }.call();
  }

  final _animatedListKey = GlobalKey<AnimatedListState>();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: AnimatedList(
          key: _animatedListKey,
          itemBuilder: (BuildContext context, int index,
                  Animation<double> animation) =>
              SizeTransition(
                  sizeFactor: animation.drive(Tween(begin: 0.0, end: 1.0)),
                  // the values cannot be the same, there has to be animation
                  child: Column(
                    key: UniqueKey(), // necessary
                    children: [
                      const ListTile(),
                      // other widgets don't seem to cause the same issues
                      LinearPercentIndicator(),
                    ],
                  )),
        ),
      ),
    );
  }
}

The issue is very difficult to reproduce, but with the above App, I could reproduce it on all devices I've tested (macOS + Web + Android). Also, it only seems to occur when some of the widgets are off-screen. I hope this helps. I swear the above example is the simplest I could do, took me some painstaking 2 hours. Using Flutter 3.10.2 and percent_indicator 4.2.3, though I don't think this matters.

Edit: Formatted code properly, added version numbers

Umar1312 commented 11 months ago

@diegoveloper Have you been able to fix this issue? Getting the same on our end

victormanuelfrancodev commented 11 months ago

@Umar1312 @phuppert

The problem is it.. flutter tries to draw the component before the render is finished, and to wait for this we can use the LayoutBuilder. With this, it seems that the error is fixed. Please replace line 247 of the class linear_percent_indicator.dart with this. Either way, I've already sent a PR

 var containerWidget = LayoutBuilder(
      builder: (context, constraints) {
        _containerWidth = constraints.maxWidth;
        _containerHeight = constraints.maxHeight;
        return Container(
          width: hasSetWidth ? widget.width : double.infinity,
          height: widget.lineHeight,
          padding: widget.padding,
          child: Stack(
            clipBehavior: Clip.none,
            children: [
              CustomPaint(
                key: _containerKey,
                painter: _LinearPainter(
                  isRTL: widget.isRTL,
                  progress: _percent,
                  progressColor: widget.progressColor,
                  linearGradient: widget.linearGradient,
                  backgroundColor: widget.backgroundColor,
                  barRadius: widget.barRadius ??
                      Radius.zero, // If radius is not defined, set it to zero
                  linearGradientBackgroundColor:
                  widget.linearGradientBackgroundColor,
                  maskFilter: widget.maskFilter,
                  clipLinearGradient: widget.clipLinearGradient,
                ),
                child: (widget.center != null)
                    ? Center(child: widget.center)
                    : Container(),
              ),
              if (widget.widgetIndicator != null && _indicatorWidth == 0)
                Opacity(
                  opacity: 0.0,
                  key: _keyIndicator,
                  child: widget.widgetIndicator,
                ),
              if (widget.widgetIndicator != null &&
                  _containerWidth > 0 &&
                  _indicatorWidth > 0)
                Positioned(
                  right: widget.isRTL ? percentPositionedHorizontal : null,
                  left: !widget.isRTL ? percentPositionedHorizontal : null,
                  top: _containerHeight / 2 - _indicatorHeight,
                  child: widget.widgetIndicator!,
                ),
            ],
          ),
        );
      }
    );
Umar1312 commented 11 months ago

@diegoveloper Can you please review and merge the PR? It'll help us avoid using a forked repository

diegoveloper commented 11 months ago

Umar, you don't need to fork, just point the package to his github url and branch name (in pubspec.yml) , try and see if the bug still exists.

Thanks

On Thu, Oct 5, 2023, 1:31 AM Umar Salim @.***> wrote:

@diegoveloper https://github.com/diegoveloper Can you please review and merge the PR? It'll help us avoid using a forked repository

— Reply to this email directly, view it on GitHub https://github.com/diegoveloper/flutter_percent_indicator/issues/174#issuecomment-1748372152, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABFL3UEZR7LUQGGXO7VQZO3X5ZV4XAVCNFSM56YBMJG2U5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCNZUHAZTOMRRGUZA . You are receiving this because you were mentioned.Message ID: @.***>

Umar1312 commented 11 months ago

@diegoveloper The PR from @victormanuelfrancodev seems to fix the issue. Can you please merge it if everything else seems fine?

nishalsehan commented 5 months ago

@diegoveloper this issue is not fixed yet. Can you fix this one for us?