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
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:
"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:
Hope this will help you..!