Flutter: ListView in a SimpleDialog
I want to show a SimpleDialog with ListView.builder in my Flutter app with this code:
showDialog(
context: context,
builder: (BuildContext context) {
return new SimpleDialog(
children: <Widget>[
new FittedBox(
child: new ListView(
children: <Widget>[
new Text("one"),
new Text("two"),
],
),
)
],
);
},
);
which gives this error (sorry, I couldn't wrap the logs as code because Stackoverflow complains that there's too much code):
══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter ( 4481): The following assertion was thrown during performLayout():
I/flutter ( 4481): RenderViewport does not support returning intrinsic dimensions.
I/flutter ( 4481): Calculating the intrinsic dimensions would require instantiating every child of the viewport, which
I/flutter ( 4481): defeats the point of viewports being lazy.
I/flutter ( 4481): If you are merely trying to shrink-wrap the viewport in the main axis direction, consider a
I/flutter ( 4481): RenderShrinkWrappingViewport render object (ShrinkWrappingViewport widget), which achieves that
I/flutter ( 4481): effect without implementing the intrinsic dimension API.
I/flutter ( 4481):
...
I/flutter ( 4481): Another exception was thrown: RenderBox was not laid out: RenderPhysicalShape#83d92 relayoutBoundary=up2 NEEDS-PAINT
I/flutter ( 4481): Another exception was thrown: 'package:flutter/src/rendering/shifted_box.dart': Failed assertion: line 310 pos 12: 'child.hasSize': is not true.
I/flutter ( 4481): Another exception was thrown: RenderBox was not laid out: RenderPhysicalShape#83d92 relayoutBoundary=up2
I tried using Container with specific height and width, and it works, but I want the ListView to fit itself in the Dialog.
How to include a ListView in a SimpleDialog?
you can create a separate method method for SimpleDialogOptions code below:
final SimpleDialog dialog = new SimpleDialog(
title: const Text('Select assignment'),
children: <Widget>[
new SimpleDialogOption(
onPressed: () { Navigator.pop(context); },
child: const Text('Text one'),
),
new SimpleDialogOption(
onPressed: () {},
child: const Text('Text two'),
),
],
);
return dialog;
I found a way... Although it's a bit hacky, and so there may be a better option.
You'll need this package:
import 'package:flutter/services.dart';
Create the widget:
class MyDialog extends StatefulWidget {
MyDialog ({Key key}) : super(key: key);
MyDialogState createState() => new MyDialogState();
}
class MyDialogState extends State<MyDialog> {
If the screen rotates it screws things up because the dialog maintains it's original size. You can probably fix that with a bit of effort, but I just lock it to prevent rotating, like this:
@override
initState() { super.initState();
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
}
Then I unlock it like this at the end:
@override
dispose() { super.dispose();
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
}
So that stops the dialog from screwing up. Then I get the size and width of the screen in the build method:
@override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
Then followed with this layout:
return ConstrainedBox(
constraints: BoxConstraints(maxHeight: height, maxWidth: width),
child: Column(
children: <Widget>[
Expanded(
child: GridView.count(
primary: false,
padding: const EdgeInsets.all(20.0),
crossAxisSpacing: 10.0,
crossAxisCount: 3,
children: _images
)
),
]
),
);
}
..again, I don't think it's the best, but it's been working for me so far.
Tried it with itemExtent property first, but that doesn't work.
Simply wrap the ListView in a Container with defined height and width, if your items are static.
showDialog(
context: context,
builder: (BuildContext context) {
return new SimpleDialog(
children: <Widget>[
new Container(
height: 100.0,
width: 100.0,
child: new ListView(
children: <Widget>[
new Text("one"),
new Text("two"),
],
),
)
],
);
},
);
showDialog(
context: context,
builder: (BuildContext context) {
return new SimpleDialog(
children: <Widget>[
new FittedBox(
child: new ListView(
children: <Widget>[
new Text("one"),
new Text("two"),
],
),
)
],
);
},
);
which gives this error (sorry, I couldn't wrap the logs as code because Stackoverflow complains that there's too much code):
══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter ( 4481): The following assertion was thrown during performLayout():
I/flutter ( 4481): RenderViewport does not support returning intrinsic dimensions.
I/flutter ( 4481): Calculating the intrinsic dimensions would require instantiating every child of the viewport, which
I/flutter ( 4481): defeats the point of viewports being lazy.
I/flutter ( 4481): If you are merely trying to shrink-wrap the viewport in the main axis direction, consider a
I/flutter ( 4481): RenderShrinkWrappingViewport render object (ShrinkWrappingViewport widget), which achieves that
I/flutter ( 4481): effect without implementing the intrinsic dimension API.
I/flutter ( 4481):
...
I/flutter ( 4481): Another exception was thrown: RenderBox was not laid out: RenderPhysicalShape#83d92 relayoutBoundary=up2 NEEDS-PAINT
I/flutter ( 4481): Another exception was thrown: 'package:flutter/src/rendering/shifted_box.dart': Failed assertion: line 310 pos 12: 'child.hasSize': is not true.
I/flutter ( 4481): Another exception was thrown: RenderBox was not laid out: RenderPhysicalShape#83d92 relayoutBoundary=up2
I tried using Container with specific height and width, and it works, but I want the ListView to fit itself in the Dialog.
How to include a ListView in a SimpleDialog?
you can create a separate method method for SimpleDialogOptions code below:
final SimpleDialog dialog = new SimpleDialog(
title: const Text('Select assignment'),
children: <Widget>[
new SimpleDialogOption(
onPressed: () { Navigator.pop(context); },
child: const Text('Text one'),
),
new SimpleDialogOption(
onPressed: () {},
child: const Text('Text two'),
),
],
);
return dialog;
I found a way... Although it's a bit hacky, and so there may be a better option.
You'll need this package:
import 'package:flutter/services.dart';
Create the widget:
class MyDialog extends StatefulWidget {
MyDialog ({Key key}) : super(key: key);
MyDialogState createState() => new MyDialogState();
}
class MyDialogState extends State<MyDialog> {
If the screen rotates it screws things up because the dialog maintains it's original size. You can probably fix that with a bit of effort, but I just lock it to prevent rotating, like this:
@override
initState() { super.initState();
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
}
Then I unlock it like this at the end:
@override
dispose() { super.dispose();
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
}
So that stops the dialog from screwing up. Then I get the size and width of the screen in the build method:
@override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
Then followed with this layout:
return ConstrainedBox(
constraints: BoxConstraints(maxHeight: height, maxWidth: width),
child: Column(
children: <Widget>[
Expanded(
child: GridView.count(
primary: false,
padding: const EdgeInsets.all(20.0),
crossAxisSpacing: 10.0,
crossAxisCount: 3,
children: _images
)
),
]
),
);
}
..again, I don't think it's the best, but it's been working for me so far.
Tried it with itemExtent property first, but that doesn't work.
Simply wrap the ListView in a Container with defined height and width, if your items are static.
showDialog(
context: context,
builder: (BuildContext context) {
return new SimpleDialog(
children: <Widget>[
new Container(
height: 100.0,
width: 100.0,
child: new ListView(
children: <Widget>[
new Text("one"),
new Text("two"),
],
),
)
],
);
},
);
Comments
Post a Comment