skip to Main Content

I have a button that creates a new a navigation route, using the same build method as the page it’s in.

onPressed: () {
                Navigator.push(
                        context,
                        MaterialPageRoute(builder: (context) => ReadDb(value)),
                      );
                    },

Calling the build method, this error gets thrown and the new route is not displayed correctly:

Exception caught by widgets library ═══════════════════════════════════
The following assertion was thrown while applying parent data.:
Incorrect use of ParentDataWidget.
The ParentDataWidget Expanded(flex: 1) wants to apply ParentData of type FlexParentData to a RenderObject, which has been set up to accept ParentData of incompatible type ParentData.
Usually, this means that the Expanded widget has the wrong ancestor RenderObjectWidget. Typically, Expanded widgets are placed directly inside Flex widgets.
The offending Expanded is currently placed inside a Semantics widget.
The ownership chain for the RenderObject that received the incompatible parent data was:
_ScrollSemantics-[GlobalKey#b3e7b] ← NotificationListener<ScrollMetricsNotification> ← Scrollable ← PrimaryScrollController ← SingleChildScrollView ← Expanded ← FutureBuilder<Map<String, dynamic>> ← ReadDb ← Semantics ← Builder ← ⋯

When the exception was thrown, this was the stack:
#0 RenderObjectElement._updateParentData.<anonymous closure> (package:flutter/src/widgets/framework.dart:6512:11)
framework.dart:6512
#1 RenderObjectElement._updateParentData (package:flutter/src/widgets/framework.dart:6529:6)
framework.dart:6529
#2 RenderObjectElement.attachRenderObject (package:flutter/src/widgets/framework.dart:6572:7)
framework.dart:6572
#3 RenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6436:5)
framework.dart:6436
#4 SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6735:11)
framework.dart:6735
Normal element mounting (33 frames)
#37 Element.inflateWidget (package:flutter/src/widgets/framework.dart:4326:16)
framework.dart:4326
#38 Element.updateChild (package:flutter/src/widgets/framework.dart:3831:20)
framework.dart:3831
#39 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5496:16)
framework.dart:5496
#40 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5634:11)
framework.dart:5634
#41 Element.rebuild (package:flutter/src/widgets/framework.dart:5187:7)
framework.dart:5187
#42 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2895:19)
framework.dart:2895
#43 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:984:21)
binding.dart:984
#44 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:457:5)
binding.dart:457
#45 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1325:15)
binding.dart:1325
#46 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1255:9)
binding.dart:1255
#47 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1113:5)
binding.dart:1113
#48 _invoke (dart:ui/hooks.dart:312:13)
hooks.dart:312
#49 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:383:5)
platform_dispatcher.dart:383
#50 _drawFrame (dart:ui/hooks.dart:283:31)
hooks.dart:283

This is the build method. It works correctly for the first route but not for the others created by pressing the button.

class ReadDb extends StatelessWidget {
  final String documentId;

  const ReadDb(this.documentId, {super.key});

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<Map<String, dynamic>>(
      future: fetchDocument(documentId),
      builder:
          (BuildContext context, AsyncSnapshot<Map<String, dynamic>> snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          if (snapshot.hasError) {
            print('Error: ${snapshot.error}');
            return Text('Error: ${snapshot.error}');
          } else {
            var data = snapshot.data;
            // print('$data');
            List<Widget> list = displayBasedOnType(context, documentId, data!);

            //print(list);
            return Expanded(
                child: SingleChildScrollView(
              child: SafeArea(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: list,
                ),
              ),
            ));
          }
        } else {
          return const Text("loading");
        }
      },
    );
  }
}

Some screenshots for reference:
https://imgur.com/a/GMTyCGU

I tried removing the Expanded widget (or wrapping it in Flex or Column), but I get an overflow error.

Edit: Adding displayBasedOnType function code:

List<Widget> displayBasedOnType(
    BuildContext context, String documentId, Map<String, dynamic> data) {
  var tipo = data['tipo'];

  List<Widget> widgets = [];
  widgets.add(
    // Add title
    Padding(
      padding: const EdgeInsets.symmetric(vertical: 8.0),
      child: Center(
        child: Text(
          documentId, // Add this line
          style: const TextStyle(
              fontSize: 24, fontWeight: FontWeight.bold), // And this line
        ),
      ),
    ),
  );
  // Add image
  // widgets.add(FutureBuilder<Widget>(
  //   future: displayImage(documentId),
  //   builder: (context, snapshot) {
  //     if (snapshot.hasData) {
  //       return (snapshot.data!);
  //     } else if (snapshot.hasError) {
  //       return Text('${snapshot.error}'); // this line prints the error
  //     }

  //     // By default, show a loading spinner.
  //     return const CircularProgressIndicator();
  //   },
  // ));

  switch (tipo) {
    case "Persona":
      {
        // Data e materie
        DateTime nascita = (data['nascita']).toDate();
        String convertedNascita = DateFormat('yyyy').format(nascita);
        DateTime morte = (data['morte']).toDate();
        String convertedMorte = DateFormat('yyyy').format(morte);
        widgets.add(
          Center(
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Text(
                    "($convertedNascita - $convertedMorte)",
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: displayMaterie(data),
                )
              ],
            ),
          ),
        );
        // Descrizione
        widgets.add(
          Padding(
            padding: const EdgeInsets.all(16),
            child: displayDescription(data),
          ),
        );
      }
      widgets.add(FutureBuilder<List<Widget>>(
          future: displayConnections(context, data),
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: snapshot.data!,
              );
            } else if (snapshot.hasError) {
              return Text('${snapshot.error}'); // this line prints the error
            }
            return const CircularProgressIndicator();
          }));
  }

  return widgets;
}

Returns Text and TextButtons.

displayConnections() function

Future<List<Widget>> displayConnections(
    BuildContext context, Map<String, dynamic> data) async {
  List<Widget> widgets = [];
  
  for (var entry in data.entries) {
    if (!toExcludeFromList.contains(entry.key) && (entry.value is List)) {
      widgets.add(
        Padding(
            padding: const EdgeInsets.fromLTRB(16, 12, 16, 12),
            child: Text(
              entry.key.capitalize(),
              style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
            )),
      );
      for (String value in entry.value) {
        bool valueExists = await documentExists(value);
        if (valueExists) {
          widgets.add((Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Padding(
                  padding: const EdgeInsets.fromLTRB(24, 8, 0, 8),
                  child: TextButton(
                    style: TextButton.styleFrom(
                      textStyle: const TextStyle(color: Colors.blue),
                      padding: EdgeInsets.zero,
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(0),
                      ),
                      tapTargetSize: MaterialTapTargetSize.shrinkWrap,
                      visualDensity: VisualDensity.compact,
                      minimumSize: const Size(0, 0),
                    ),
                    onPressed: () {
                      Navigator.push(
                        context,
                        MaterialPageRoute(builder: (context) => ReadDb(value)),
                      );
                    },
                    child: Text(value),
                  ))
            ],
          )));
        } else {
          widgets.add((Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Padding(
                  padding: const EdgeInsets.fromLTRB(24, 8, 0, 8),
                  child: Text(value))
            ],
          )));
        }
      }
    }
  }
  return widgets;
}

2

Answers


  1. Here an Example in how you should put the widgets, some widgets have especific parents where they can be used, always check at the widget examples or internal code to verify that:

    import 'package:flutter/material.dart';
    
    const 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: const MainPage(),
        );
      }
    }
    
    class MainPage extends StatelessWidget {
      const MainPage({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: TextButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => const MyWidget(),
                  ),
                );
              },
              child: const Text("Example"),
            ),
          ),
        );
      }
    }
    
    class MyWidget extends StatelessWidget {
      const MyWidget();
    
      Future<Map<String, dynamic>> fetchDocument(String documentId) async {
        await Future.delayed(const Duration(seconds: 1));
    
        return {
          "data": documentId,
          "title": "Title",
          "tipo": "Persona",
        };
      }
    
      List<Widget> displayBasedOnType(
          BuildContext context, String documentId, Map<String, dynamic> data) {
        var tipo = data['tipo'];
    
        List<Widget> widgets = [];
        widgets.add(
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 8.0),
            child: Center(
              child: Text(
                documentId,
                style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
              ),
            ),
          ),
        );
    
        if (tipo == "Persona") {
          String convertedNascita = "1/30/2024";
          String convertedMorte = "1/29/2024";
          widgets.add(
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Text(
                    "($convertedNascita - $convertedMorte)",
                  ),
                ),
                const Padding(
                  padding: EdgeInsets.all(8.0),
                  child: Text("Hola"),
                )
              ],
            ),
          );
          // Descrizione
          widgets.add(
            const Padding(
              padding: EdgeInsets.all(16),
              child: Text(
                  "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."),
            ),
          );
    
          widgets.add(
            const Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text("Hola"),
                Text("Hola"),
                Text("Hola"),
                Text("Hola"),
                Text("Hola"),
                Text("Hola"),
              ],
            ),
          );
    
          return widgets;
        } else {
          return [
            const SizedBox.shrink(),
          ];
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return FutureBuilder<Map<String, dynamic>>(
          future: fetchDocument("123"),
          builder:
              (BuildContext context, AsyncSnapshot<Map<String, dynamic>> snapshot) {
            if (snapshot.connectionState == ConnectionState.done) {
              if (snapshot.hasError) {
                print('Error: ${snapshot.error}');
                return Text('Error: ${snapshot.error}');
              } else {
                var data = snapshot.data;
    
                List<Widget> list = displayBasedOnType(context, "123", data!);
    
                return SafeArea(
                  child: Scaffold(
                    body: SingleChildScrollView(
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.center,
                        children: [
                          ...list,
                        ],
                      ),
                    ),
                  ),
                );
              }
            } else {
              return const SafeArea(
                child: Scaffold(
                  body: Center(
                    child: Text("loading"),
                  ),
                ),
              );
            }
          },
        );
      }
    }
    
    Login or Signup to reply.
  2. "Incorrect-Use-Of-ParentDataWidget" error basically occured when we wrap our widget which takes all vertical space (such as column, listview, singlechildscrollview etc) with ‘Expanded()’ widget.

    Remove this ‘Expanded()’ widget from singleChildScrollView.

    if it throws overflows than do one or more things as foll0ws:

    • wrap this specific widget with Expanded() (if not works than try to wrap with ‘Flexible()’
    • if you use listView than use shrinkWrap: true and physics: NeverScrollableScrollPhysics() and then wrap this ‘listView’ with singleChildScrollView.
    • try to add mainAxisSize: MainAxisSize.min in column or row.
    • if overflow renders by useing long texts than use overflow: TextOverflow.ellipsis property of ‘Text()’ widget. (in case not work, wrap this text with Expanded or Flexible widget).

    Hope this will help you..!

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search