Search code examples
flutterlayoutkey

key of Container "vanishes" when trying to get its size


I am trying to get the size of a container whith a function that typically works. Now it fails according to the debugger because it cannot find the container's key in the widget tree. The error is The method 'findRenderObject' was called on null. Receiver: null I do see the key in getSize() but when stepping into the error throwing line, I find the explanation that it cannot find the widget if null is returned. Any idea why this is so?

import 'package:flutter/material.dart';

final Color darkBlue = Color.fromARGB(255, 18, 32, 47);

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
 @override
  _MyWidgetState createState() => _MyWidgetState();
}


class _MyWidgetState extends State<MyWidget>  {
  GlobalKey _keyScreenContainer = GlobalKey(); // <-------- key declared
   @override
  Widget build(BuildContext context) {
    return SafeArea(
          child: Container(
            key: _keyScreenContainer,         // <--------- key allocated
            width: 20, height: 20,
            child: Text("${getSize(_keyScreenContainer, context)}"),
            )
      );
  }
  
  Size getSize(GlobalKey _key, BuildContext context) {
    final RenderBox renderBox = _key.currentContext.findRenderObject(); // <---- error
    final boxSize = renderBox.size;
    print (boxSize);
    return boxSize;
  }
}

Solution

  • The error is because you are calling the getSize function even before the build is complete. You may call the function once widget layout is complete either in initState with WidgetsBinding.instance .addPostFrameCallback((_) => someFunction()) or from with something like a button. Please see the code below :

    import 'package:flutter/material.dart';
    
    final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
          debugShowCheckedModeBanner: false,
          home: Scaffold(
            body: Center(
              child: MyWidget(),
            ),
          ),
        );
      }
    }
    
    class MyWidget extends StatefulWidget {
     @override
      _MyWidgetState createState() => _MyWidgetState();
    }
    
    
    class _MyWidgetState extends State<MyWidget>  {
      GlobalKey _keyScreenContainer = GlobalKey();
      
      @override
      void initState(){
        
                super.initState();
        
        WidgetsBinding.instance
            .addPostFrameCallback((_) => print("${getSize(_keyScreenContainer, context)}"));
        
      }
       @override
      Widget build(BuildContext context) {
        return Column(children: [
              Container(
                key: _keyScreenContainer,     
                width: 20, height: 20,
                child: Text("abc"),
          ), RaisedButton(onPressed:(){
                print("${getSize(_keyScreenContainer, context)}");
                
                
              },child:Text("Get size"))]);
      }
      
      Size getSize(GlobalKey key, BuildContext context) {
        final RenderBox renderBox = key.currentContext.findRenderObject(); // <---- error
        final boxSize = renderBox.size;
        print (boxSize);
        return boxSize;
      }
    }