Skip to content

Instantly share code, notes, and snippets.

@raison00
Created May 1, 2020 20:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save raison00/2ebedc6a99cd8b5bbe68d6689a4223c8 to your computer and use it in GitHub Desktop.
Save raison00/2ebedc6a99cd8b5bbe68d6689a4223c8 to your computer and use it in GitHub Desktop.
CustomMultiChildLayout with flexible vs non-flexible widgets
import 'package:flutter/material.dart';
// This example is adapted from https://stackoverflow.com/questions/51304568/
class ScaffoldContextError extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Unbounded Viewport Error',
theme: ThemeData(
primarySwatch: Colors.blue,
scaffoldBackgroundColor: const Color(0xFF442F43),
),
home: Scaffold(
body: Column(
children: <Widget>[
// Resolution: wrap GridSearch inside an Expanded widget or
// a widget with a fixed height such as a Container.
Expanded(
child: GridSearch(),
),
],
),
));
}
}
class GridSearch extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
scaffoldBackgroundColor: const Color(0xFF442F43),
),
home: MyFlutterPage(title: 'Flutter Layout Exercises'),
);
}
}
class MyFlutterPage extends StatefulWidget {
MyFlutterPage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyFlutterPageState createState() => _MyFlutterPageState();
}
class _MyFlutterPageState extends State<MyFlutterPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Padding(
padding: EdgeInsets.only(left: 30.0),
child: CustomMultiChildLayout(
delegate: YourLayoutDelegate(),
children: <Widget>[
LayoutId(
id: 1,
// You will need to refer to that id when laying out your children.
child: new Row(children: [
//
new Container(
width: 85.0,
decoration: new BoxDecoration(
border: Border.all(width: 6, color: Colors.lightBlue),
color: const Color(0xFF442F43),
borderRadius:
const BorderRadius.all(const Radius.circular(12)),
),
child: Padding(
padding: EdgeInsets.only(
right: 10, left: 10, top: 15, bottom: 15),
child: new Text(
"The Card widget tries to be just large enough to accomodate its child. The height is not hard-coded, allowing it to dynamically update its size based on the text content.",
style: TextStyle(
fontSize: 14,
color: Colors.cyanAccent,
fontFamily: 'Sans',
fontWeight: FontWeight.w300,
),
),
),
),
//
]),
),
LayoutId(
id: 2,
// You will need to refer to the id when laying out the children.
child: new Row(children: [
//
// This will take up 150dp always, since it is not wrapped by a Expanded
new Container(
width: 150.0,
decoration: new BoxDecoration(
border: Border.all(
width: 13,
color: Color(0xFF442F43),
),
color: Colors.green[900],
borderRadius:
const BorderRadius.all(const Radius.circular(3)),
),
child: Padding(
padding: EdgeInsets.only(
right: 10, left: 10, top: 15, bottom: 15),
child: new Text(
"The Card widget is NOT wrapped in a flexible widget. It has a width of 150 and will always occupy this 150 of space because it isn't wrapped in a widget. To contrast the widget card next to it, it won't try to have a dynamic height, instead it displays the fill height coded in the container: 500. ",
style: TextStyle(
fontSize: 14,
color: Colors.cyanAccent,
fontFamily: 'Sans',
fontWeight: FontWeight.w300,
),
),
),
),
// chartuse Container
// This will take up the remaining space of the row with a flex 2 set expanding the content and avoiding a render overflow of the text
new Expanded(
flex: 2,
child: new Container(
width: 220.0,
height: 600.0,
decoration: new BoxDecoration(
border: Border.all(
width: 15,
color: const Color(0xFF442F43),
),
color: Colors.yellow[200],
borderRadius:
const BorderRadius.all(const Radius.circular(5)),
),
child: new Padding(
padding: EdgeInsets.only(
right: 10, left: 10, top: 15, bottom: 15),
child: new Text(
"This is coded at 220 wide, 600 long, and wrapped in an expanded widget and having a flex of 2. This tries to be just large enough to accomodate its child. This will take up 2/3 of the remaining space because it has a flex factor of 2. The next item seen as an orange and deep purple column, it's 750 wide, but has a flex of 1, so this smaller container is larger due to the flex factor of 2. The content here shows it can cascade down, accomdating the text flow and not causing an overflow error.",
style: TextStyle(
fontSize: 14,
color: Colors.deepPurpleAccent,
fontFamily: 'Sans',
fontWeight: FontWeight.w800,
), //text style
), //text
), //padding
), //container
),
//row
// orange
// This is coded to 750 wide with a flex of 1. it does not appear widest on screen.
new Expanded(
flex: 1,
child: new Container(
width: 750.0,
height: 450.0,
decoration: new BoxDecoration(
border: Border.all(
width: 8,
color: const Color(0xFF442F43),
),
color: Colors.deepOrange,
borderRadius:
const BorderRadius.all(const Radius.circular(18)),
),
child: new Padding(
padding: EdgeInsets.only(
right: 10, left: 10, top: 15, bottom: 15),
child: new Text(
"This is coded to 750 wide with a flex of 1. It does not appear widest on screen because it has a flex factor of 1. so this smaller container is actually larger due to the flex factor of 1. The content here shows text can cascade down, accomdating the text flow and not causing an overflow error.",
style: TextStyle(
fontSize: 13,
color: Colors.cyanAccent,
fontFamily: 'Sans',
fontWeight: FontWeight.w800,
), //text style
), //text
), //padding
), //continer
)
//expanded
]),
),
],
),
),
),
);
}
}
class YourLayoutDelegate extends MultiChildLayoutDelegate {
// You can pass any parameters to this class because you will instantiate your delegate
// in the build function where you place your CustomMultiChildLayout.
// I will use an Offset for this simple example.
YourLayoutDelegate({this.position});
final Offset position;
@override
void performLayout(Size size) {
// `size` is the size of the `CustomMultiChildLayout` itself.
Size leadingSize = Size
.zero; // If there is no widget with id `1`, the size will remain at zero.
// Remember that `1` here can be any **id** - you specify them using LayoutId.
if (hasChild(1)) {
leadingSize = layoutChild(
1, // The id once again.
BoxConstraints.tightFor(
height: size
.height), // This just says that the child cannot be bigger than the whole layout.
);
// No need to position this child if we want to have it at Offset(0, 0).
}
if (hasChild(2)) {
final secondSize = layoutChild(
2,
BoxConstraints.tightFor(width: size.width / 2),
);
positionChild(
2,
Offset(
leadingSize.width, // This will place child 2 to the right of child 1.
size.height / 2 -
secondSize.height / 2, // Centers the second child vertically.
),
);
}
}
@override
bool shouldRelayout(YourLayoutDelegate oldDelegate) {
return oldDelegate.position != position;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment