I have a web application with the following layout:
I am trying to create a flutter application with a similar layout and this is what I have so far:
For reproduction purposes, my layout logic is the following (all my code is in the main.dart
file for this example):
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Assemblers Tasks',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.deepOrange,
),
home: MyHomePage(title: 'Assembly Tasks'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String dropdownValue;
List<Map<String, dynamic>> buildItems = [];
getBuilds() {
List<Map<String, dynamic>> items = [];
items.add({"id": 10, "vehicleModel": "A10", "vehicleNumber": "TEST-00010"});
setState(() {
buildItems = items;
});
}
List<Map<String, dynamic>> buildSections = [];
getSections() {
List<Map<String, dynamic>> items = [];
items.add({
"id": 5,
"section": "Front",
});
items.add({
"id": 15,
"section": "Rear",
});
setState(() {
buildSections = items;
});
}
Future<List<Map<String, dynamic>>> getSystems(String buildSectionId) async {
List<Map<String, dynamic>> items = [];
if (int.parse(buildSectionId) == 5) {
items.add({
"id": 4,
"system": "Hydraulics",
});
items.add({
"id": 20,
"system": "High Voltage",
});
}
return items;
}
@override
void initState() {
getBuilds();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
padding: EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Container(
width: 275.0,
child: DropdownButton(
value: dropdownValue,
hint: Text("Choose Build"),
isExpanded: true,
items: buildItems
.map<Map<String, String>>((Map<String, dynamic> item) {
String id = item["id"].toString();
String name = item["vehicleModel"] + " " + item["vehicleNumber"];
return {"id": id, "name": name};
})
.toList()
.map<DropdownMenuItem<String>>((Map<String, String> item) {
return DropdownMenuItem<String>(
value: item["id"],
child: Text(item["name"]),
);
})
.toList(),
onChanged: (String newValue) {
getSections();
setState(() {
dropdownValue = newValue;
});
}),
),
],
),
Row(
children: <Widget>[
Container(
width: 150.0,
height: 60.0,
color: Colors.black,
child: Align(
alignment: Alignment.center,
child: Text(
"SECTION",
style: TextStyle(
color: Colors.white,
fontSize: 17.3,
letterSpacing: 1.35,
),
),
),
),
Container(
width: 150.0,
height: 60.0,
color: Color(0xff444444),
child: Align(
alignment: Alignment.center,
child: Text(
"SYSTEM",
style: TextStyle(
color: Colors.white,
fontSize: 17.3,
letterSpacing: 1.35,
),
),
),
),
Expanded(
child: Container(
height: 60.0,
padding: EdgeInsets.only(left: 36.0),
margin: EdgeInsets.only(right: 72.0),
color: Color(0xff666666),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
"TASK",
style: TextStyle(
color: Colors.white,
fontSize: 17.3,
letterSpacing: 1.35,
),
),
),
),
)
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Container(
decoration: BoxDecoration(border: Border.all(color: Colors.black12, width: 1.0, style: BorderStyle.solid)),
height: MediaQuery.of(context).size.height - 225,
child: ListView.builder(
shrinkWrap: true,
itemCount: buildSections.length,
itemBuilder: (BuildContext context, int index) {
String section = buildSections[index]["section"] != null ? buildSections[index]["section"] : "";
String buildSectionId = buildSections[index]["id"].toString();
return Row(
children: <Widget>[
Container(
width: 150.0,
decoration: BoxDecoration(
border: Border(
right: BorderSide(
color: Colors.black12,
width: 1.0,
),
bottom: BorderSide(
color: Colors.black12,
width: 1.0,
),
),
),
padding: EdgeInsets.fromLTRB(0.0, 16.0, 0.0, 16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Align(
alignment: Alignment.center,
child: Center(
child: RotatedBox(
quarterTurns: -1,
child: Text(
section.toUpperCase(),
style: TextStyle(
fontSize: 15.0,
letterSpacing: 1.2,
),
),
),
),
),
Padding(
padding: EdgeInsets.all(12.0),
),
Align(
alignment: Alignment.center,
child: FloatingActionButton(
child: Icon(Icons.image),
),
),
],
),
),
FutureBuilder(
future: getSystems(buildSectionId),
builder: (BuildContext context, AsyncSnapshot systemsSnap) {
if (systemsSnap.connectionState == ConnectionState.waiting) {
return Container(
height: 100.0,
width: 200.0,
child: Text("Please wait..."),
);
} else if (systemsSnap.hasError) {
return Container(
height: 100.0,
width: 200.0,
child: Text("Oops! There was an error!"),
);
}
return Row(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width - 256.0,
child: ListView.builder(
shrinkWrap: true,
itemCount: systemsSnap.data.length,
itemBuilder: (context, index) {
Map<String, dynamic> system = systemsSnap.data[index];
String systemName = system["system"];
return Row(
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(0.0, 16.0, 0.0, 16.0),
width: 150.0,
decoration: BoxDecoration(
border: Border(
right: BorderSide(
color: Colors.black12,
width: 1.0,
),
bottom: BorderSide(
color: Colors.black12,
width: 1.0,
),
),
),
child: Column(
children: <Widget>[
Align(
alignment: Alignment.center,
child: RotatedBox(
quarterTurns: -1,
child: Text(
systemName.toUpperCase(),
style: TextStyle(
fontSize: 15.0,
letterSpacing: 1.2,
),
),
),
),
Padding(
padding: EdgeInsets.all(12.0),
),
Align(
alignment: Alignment.center,
child: FloatingActionButton(
child: Icon(Icons.image),
),
),
],
),
),
],
);
},
),
),
],
);
},
),
],
);
},
),
),
),
Container(
padding: EdgeInsets.fromLTRB(16.0, 16.0, 0.0, 0.0),
child: Column(
children: <Widget>[
Container(
child: FloatingActionButton(
child: Icon(Icons.photo_library),
onPressed: () {
//TODO action
},
),
),
Padding(
padding: EdgeInsets.all(10.0),
),
Container(
child: FloatingActionButton(
child: Icon(Icons.library_books),
onPressed: () {
//TODO action
},
),
),
Padding(
padding: EdgeInsets.all(10.0),
),
Container(
child: FloatingActionButton(
child: Icon(Icons.list),
onPressed: () {
//TODO action
},
),
),
Padding(
padding: EdgeInsets.all(10.0),
),
Container(
child: FloatingActionButton(
child: Icon(Icons.history),
onPressed: () {
//TODO action
},
),
),
],
),
),
],
),
],
),
),
);
}
}
The above code is ready to be pasted into the main.dart file and preview on a the virtual device (preferably tablet).
So far I have tried the solutions I found on these posts to no avail:
- Make container widget fill parent vertically
- Flutter Container height same as parent height
- Flutter expand Container to fill remaining space of Row
- The equivalent of wrap_content and match_parent in flutter?
Since the Row that contains the section Container also has a ListView being generated with the FutureBuilder, the height of the Row automatically expands to fit the ListView. I also want the section Container to expand to the same height as the how the Row widget is expanding; i.e., The bottom border of the section Container that says FRONT, should be aligned with the bottom border of the Hight Voltage system and the right border of the FRONT section Container, should go all the way to the top.
I already spent 3 days without a resolution.
I have tried the suggestion on the answer provided by @MaadhavSharma but I get the following exception:
════════ Exception Caught By rendering library ════════════════════════════
The following assertion was thrown during performLayout(): BoxConstraints forces an infinite height.
I changed a little the structure to make it work, here is the entire build()
method:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
padding: EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Container(
width: 275.0,
child: DropdownButton(
value: dropdownValue,
hint: Text("Choose Build"),
isExpanded: true,
items: buildItems
.map<Map<String, String>>((Map<String, dynamic> item) {
String id = item["id"].toString();
String name = item["vehicleModel"] + " " + item["vehicleNumber"];
return {"id": id, "name": name};
})
.toList()
.map<DropdownMenuItem<String>>((Map<String, String> item) {
return DropdownMenuItem<String>(
value: item["id"],
child: Text(item["name"]),
);
})
.toList(),
onChanged: (String newValue) {
getSections();
setState(() {
dropdownValue = newValue;
});
}),
),
],
),
Row(
children: <Widget>[
Container(
width: 150.0,
height: 60.0,
color: Colors.black,
child: Align(
alignment: Alignment.center,
child: Text(
"SECTION",
style: TextStyle(
color: Colors.white,
fontSize: 17.3,
letterSpacing: 1.35,
),
),
),
),
Container(
width: 150.0,
height: 60.0,
color: Color(0xff444444),
child: Align(
alignment: Alignment.center,
child: Text(
"SYSTEM",
style: TextStyle(
color: Colors.white,
fontSize: 17.3,
letterSpacing: 1.35,
),
),
),
),
Expanded(
child: Container(
height: 60.0,
padding: EdgeInsets.only(left: 36.0),
margin: EdgeInsets.only(right: 72.0),
color: Color(0xff666666),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
"TASK",
style: TextStyle(
color: Colors.white,
fontSize: 17.3,
letterSpacing: 1.35,
),
),
),
),
)
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Container(
decoration: BoxDecoration(border: Border.all(color: Colors.black12, width: 1.0, style: BorderStyle.solid)),
height: MediaQuery.of(context).size.height - 225,
child: ListView.builder(
shrinkWrap: true,
itemCount: buildSections.length,
itemBuilder: (BuildContext context, int index) {
String section = buildSections[index]["section"] != null ? buildSections[index]["section"] : "";
String buildSectionId = buildSections[index]["id"].toString();
return IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
width: 150.0,
decoration: BoxDecoration(
color: Colors.green,
border: Border(
right: BorderSide(
color: Colors.black12,
width: 1.0,
),
bottom: BorderSide(
color: Colors.black12,
width: 1.0,
),
),
),
padding: EdgeInsets.fromLTRB(0.0, 16.0, 0.0, 16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Align(
alignment: Alignment.center,
child: Center(
child: RotatedBox(
quarterTurns: -1,
child: Text(
section.toUpperCase(),
style: TextStyle(
fontSize: 15.0,
letterSpacing: 1.2,
),
),
),
),
),
Padding(
padding: EdgeInsets.all(12.0),
),
Align(
alignment: Alignment.center,
child: FloatingActionButton(
child: Icon(Icons.image),
),
),
],
),
),
FutureBuilder(
future: getSystems(buildSectionId),
builder: (BuildContext context, AsyncSnapshot systemsSnap) {
if (systemsSnap.connectionState == ConnectionState.waiting) {
return Container(
height: 100.0,
width: 200.0,
child: Text("Please wait..."),
);
} else if (systemsSnap.hasError) {
return Container(
height: 100.0,
width: 200.0,
child: Text("Oops! There was an error!"),
);
}
return
Container(
width: MediaQuery.of(context).size.width - 256.0,
child: Column(
children: systemsSnap.data.map<Widget>((e) => Container(
padding: EdgeInsets.fromLTRB(0.0, 16.0, 0.0, 16.0),
width: 150.0,
decoration: BoxDecoration(
border: Border(
right: BorderSide(
color: Colors.black12,
width: 1.0,
),
bottom: BorderSide(
color: Colors.black12,
width: 1.0,
),
),
),
child: Column(
children: <Widget>[
Align(
alignment: Alignment.center,
child: RotatedBox(
quarterTurns: -1,
child: Text(
e["system"].toUpperCase(),
style: TextStyle(
fontSize: 15.0,
letterSpacing: 1.2,
),
),
),
),
Padding(
padding: EdgeInsets.all(12.0),
),
Align(
alignment: Alignment.center,
child: FloatingActionButton(
child: Icon(Icons.image),
),
),
],
),
)).toList(),
),
);
// Row(
// children: <Widget>[
// Container(
// width: MediaQuery.of(context).size.width - 256.0,
// child: ListView.builder(
// shrinkWrap: true,
// itemCount: systemsSnap.data.length,
// itemBuilder: (context, index) {
// Map<String, dynamic> system = systemsSnap.data[index];
// String systemName = system["system"];
// return Row(
// children: <Widget>[
//
// ],
// );
// },
// ),
// ),
// ],
// );
},
),
],
),
);
},
),
),
),
Container(
padding: EdgeInsets.fromLTRB(16.0, 16.0, 0.0, 0.0),
child: Column(
children: <Widget>[
Container(
child: FloatingActionButton(
child: Icon(Icons.photo_library),
onPressed: () {
//TODO action
},
),
),
Padding(
padding: EdgeInsets.all(10.0),
),
Container(
child: FloatingActionButton(
child: Icon(Icons.library_books),
onPressed: () {
//TODO action
},
),
),
Padding(
padding: EdgeInsets.all(10.0),
),
Container(
child: FloatingActionButton(
child: Icon(Icons.list),
onPressed: () {
//TODO action
},
),
),
Padding(
padding: EdgeInsets.all(10.0),
),
Container(
child: FloatingActionButton(
child: Icon(Icons.history),
onPressed: () {
//TODO action
},
),
),
],
),
),
],
),
],
),
),
);
}
Basically I changed the ListView
of the second element of the Row
for a Column
, since it already was inside a ListView
and that was making it have double scroll and the heights weren't expanding the height of the row properly, and also I wrapped the Row
inside an IntrinsicHeight
and put crossAxisAlignment: CrossAxisAlignment.stretch
to the Row
so the content will fit the height of the Row
.
The use of IntrinsicHeight
is expensive, but I don't see another solution for the way you structured the widgets. I recommend you to try to optimize all the structure so you could find a better and optimal solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With