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 #210

Open garbidge opened 3 months ago

garbidge commented 3 months ago

Fixes issue https://github.com/diegoveloper/flutter_percent_indicator/issues/175

Description:

It seems like this can at times be called before it has been through layout (in particular when restoring state). Changed to first check hasSize before using size.

Reproduction steps:

Using minimal sample code included below:

If relevant, this was reproduced on Android 12, Flutter 3.22.0

Sample code:

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  Widget getView(BuildContext subContext, RouteSettings routeSettings) {
    switch (routeSettings.name) {
      case WidgetB.routeName:
        return const WidgetB();
      default:
        return const WidgetA();
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      restorationScopeId: "test",
      onGenerateRoute: (RouteSettings routeSettings) {
        var uri = Uri.parse(routeSettings.name ?? '');
        return MaterialPageRoute<void>(
          settings: routeSettings,
          builder: (BuildContext subContext) {
            return getView(subContext, RouteSettings(
                name: uri.path,
                arguments: routeSettings.arguments ?? uri.queryParameters));
          },
        );
      },
    );
  }
}

class WidgetA extends StatelessWidget {
  static const routeName = 'widget_a';

  const WidgetA({super.key,});

  @override
  Widget build(BuildContext context) {
    return Column(children: [
      LinearPercentIndicator(),
      ElevatedButton(
        onPressed: () => Navigator.of(context).restorablePushNamed(WidgetB.routeName),
        child: const Text("Click me")
      )
    ],);
  }
}

class WidgetB extends StatelessWidget {
  static const routeName = 'widget_b';

  const WidgetB({super.key,});

  @override
  Widget build(BuildContext context) {
    return const Text("Now use device buttons to put app in background and then restore");
  }
}