Flutter layout -3 column - flutter

I am trying to create a resume document similar to the attached image. Need some help on top-level layout
Would it be:
container
children
column widget
children
container (header)
container (body)
children
column
children
row (education)
row (experience)
also, how would I get the dotted lines?
Thanks for your help

It would be:
container
children
column widget
children
container (header)
container (body)
child
row
children
column (education)
column (experience)
For Dash Lines, you can use the following Plugin Flutter Dash
Another alternative would be:
column widget
children
Row (header)
Row (body)
children
column (education)
column (experience)
To achieve the exact layout in the body section, you might want to use to Expanded Widget to achieve what you want.
column widget
children
Row (header)
Row (body)
children
Expanded [Flex 1]
child
Container (education)
Expanded [Flex 2]
child
Container (experience)
For Dash to work:
You need to add flutter_dash: ^0.0.1 under dependencies in pubspec.yaml
import 'package:flutter/material.dart';
import 'package:flutter_dash/flutter_dash.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
routes: {
'/': (BuildContext context) => MyApp2(),
},
);
}
}
class MyApp2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Row(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height / 3,
)
],
),
Dash(
direction: Axis.horizontal,
length: MediaQuery.of(context).size.width,
dashLength: 12,
dashColor: Colors.red),
Row(
children: <Widget>[
Expanded(
child: Text('Education'),
flex: 1,
),
Dash(
direction: Axis.vertical,
length: (2 *MediaQuery.of(context).size.height) / 3 - MediaQuery.of(context).padding.top,
dashLength: 12,
dashColor: Colors.red),
Expanded(
child: Text('Experience'),
flex: 2,
),
],
),
],
);
}
}

You can try this too:
...your document...
Container(
child: Column(
children: <Widget>[
Container(
child: ....header....,
),
Container(
...body...
child: Row(
children: <Widget>[
Container(
child: ...education...
),
Container(
child: ...experience...,
),
],
),
),
],
),
);

Related

Making a card having text and image using Row and an inner Column

My card's text part has multiple text widgets that I have to put under column. I want to add this whole part under a row widget, so that I can add the image part to the right of this column widget.
This is what I've done:
class ContactMe extends StatelessWidget {
static const String route = '/contact_me';
const ContactMe({Key? key}) : super(key: key);
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
return Scaffold(
body: Column(
children: [
CommonNavBar(height: height),
Expanded(
child: FutureBuilder(
future: contactMe(),
builder: (context, snapshot) {
if (snapshot.data == null)
return Center(child: CircularProgressIndicator());
else {
var data = snapshot.data as List<String>;
return LayoutBuilder(builder: (context, constraints) {
if (constraints.maxWidth < 1000) {
return Center();
} else {
return Row( //this is parent row
children: [
Container(
child: Column( //the column that contains multiple other widgets
children: [
text('Reach Out to me!', 25,
Theme.of(context).primaryColorLight),
Text('anything'),
],
),
),
Image.asset('assets/contact_me/' + data[2], scale: 2), //the image widget
],
);
}
});
}
}),
),
],
),
);
}
}
But instead of a card, the layout looks like this:
As visible in the picture, the image for some reason is not in line with the column widget. What's the mistake I'm making here?
In continuation to #OlegBezr's answer, I fixed it by using mainAxisAlignment and crossAxisAlignment for both the widgets.
return Row(
crossAxisAlignment: CrossAxisAlignment.start, //takes the row to the top
mainAxisAlignment: MainAxisAlignment.spaceAround, //Used this for spacing between the children
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start, //used for aligning the children vertically
children: [
text('Reach Out to me!', 25,
Theme.of(context).primaryColorLight),
text(
'DISCUSS A PROJECT OR JUST WANT TO SAY HI? MY INBOX IS OPEN FOR ALL.',
18,
Theme.of(context)
.primaryColorLight
.withOpacity(0.3)),
],
),
Image.asset('assets/contact_me/' + data[2], scale: 2),
],
);
I think your problem is related to different alignments. The default crossAxisAlignment for a Row is CrossAxisAlignment.center, thus your image and column are located in the vertical middle of the row. The default mainAxisAlignment for a Column is MainAxisAlignment.start, so the content inside your column is located at its top.
I can see two possible ways to put your content on the same horizontal line:
Set mainAxisAlignment for the Column to MainAxisAlignment.center
Set crossAxisAlignment for the Row to CrossAxisAlignment.start
For the future, you might find this resource helpful when dealing with different layouts: https://docs.flutter.dev/development/ui/layout

How to make body divided into 3 equal part using container?

I want to make my screen into 3 equal part using container class in flutter. How to do that?
What you want is the Flexible widget
Let's say you want the three equal parts to be stacked vertically
return Column(
children: [
Flexible(child: Container()),
Flexible(child: Container()),
Flexible(child: Container()),
]
);
You can also specify a flex component to signify the relationship between the widgets' sizes
return Column(
children: [
Flexible(child: Container(), flex:1),
Flexible(child: Container(), flex:2),
]
);
which will make the second widget take 2/3 of the available space
I prefer using LayoutBuilder, it constraints that can be used to get body height,maxWidth, also it provides more than this. Also, you can try media query.
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) => Column(
children: [
Container(
height: constraints.maxHeight / 3,
width: constraints.maxWidth,
color: Colors.deepPurple,
),
Container(
height:size.height/3,
width: size.width/3,
color: Colors.deepPurple,
)
],
),
));
}
You can remove Column it's just an example. Using LayoutBuilder provide parents' constraints.

ListView inside Row of Flexible: Horizontal viewport was given unbounded width

This is a page of my app. I'm trying to have a space to put widgets and then a sidebar on the right.
import 'package:flutter/material.dart';
class Looper extends StatefulWidget {
#override
_LooperState createState() => _LooperState();
}
class _LooperState extends State<Looper> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Row(children: [
Flexible(
flex: 21,
child: FittedBox(
fit: BoxFit.cover,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
],
),
)
),
Flexible(
child: Container(),
flex: 2,
),
]));
}
}
But I get:
Horizontal viewport was given unbounded width.
I tried multiple BoxFit like fitHeight and fitWidth but none of them work. Changing FittedBox by a Container gives the same error but for height;
I kind of understand the error. The ListView doesn't get boundaries from where to grow. However, the Scaffold, as I imagine, already should provide those bounds. I souldn't need to make everything fit inside a Container with the width and size of the phone screen.
In such cases, you can use shrink wrap. Try this out.
Row(children: [
Flexible(
flex: 1,
child: ListView(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
children: [
Text('Shrink wrap is usefull.')
],
)
),
Flexible(
child: Container(),
flex: 1,
),
])

children have non-zero flex but incoming height constraints are unbounded

return Card(
child: Row(
children: <Widget>[
Placeholder(
fallbackHeight: 100,
fallbackWidth: 100,
),
Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(height: 10, child: Container(child: Text("One"),)),
Expanded(child: Container(child: Text("Center") )),
],
)
],
),
);
On the code above I am getting error:
I/flutter ( 4872): The following assertion was thrown during performLayout():
I/flutter ( 4872): RenderFlex children have non-zero flex but incoming height constraints are unbounded.
I/flutter ( 4872): When a column is in a parent that does not provide a finite height constraint, for example if it is
I/flutter ( 4872): in a vertical scrollable, it will try to shrink-wrap its children along the vertical axis. Setting a
I/flutter ( 4872): flex on a child (e.g. using Expanded) indicates that the child is to expand to fill the remaining
I/flutter ( 4872): space in the vertical direction.
Whole code:
class FilmItems extends StatelessWidget {
List<String> filmListList;
List<String> _getFilmList() {
var items = List<String>.generate(101, (counter) => "item $counter");
return items;
}
FilmItems() {
filmListList = _getFilmList();
}
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: filmListList.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Row(
children: <Widget>[
Placeholder(
fallbackHeight: 100,
fallbackWidth: 100,
),
Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(height: 10, child: Container(child: Text("One"),)),
Expanded(child: Container(child: Text("Center") )),
],
)
],
),
);
});
}
}
What is wrong?
The problem is that you are using Expanded and any of it's parents have an explicit height.
The solution would depend on how do you want to handle the height of the Expanded. In your case, seems to be that you want to have a Row with a fixed height equal to the Placeholder. In that case, you need to wrap the Row with the same height as the Placeholder, like this:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("")),
body: ListView.builder(
itemCount: 3,
itemBuilder: (BuildContext context, int index) {
return Card(
child: SizedBox(
height: 100,
child: Row(
children: <Widget>[
Placeholder(
fallbackHeight: 100,
fallbackWidth: 100,
),
Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text("One"),
Expanded(child: Center(child: Text("Center"))),
],
),
],
),
),
);
}),
);
}
I removed the height 10 of the Text("One") because if the fontSize is bigger, the text would look cropped. And I wrapped the Text("Center") with a Center widget, I think that's what you wanted to achieve.
Suggestion: If the content inside the Row could haven a bigger height than the Row, the content would look cropped. If that could happen you might want to take another approach.
When you are using Column widget, it's parent should have a finite height. So in your code the parent is a row and it also does not have a finite height. You need wrap Column with Container and give a finite height.
Container(
height: 500,
child: Column()
)
Put your Column/Row inside an Expanded or SizedBox (with some height) like this:
Expanded(
child: Column(...)
)
Or
SizedBox(
height: 250, // give some height
child: Column(...),
)

How to create a horizontally scrolling table with fixed column in Flutter?

I would like to create a series of tables that you can scroll through vertically, each of which may have a different number of rows/columns from each other.
Within each table, I would like to have the leftmost column frozen in place, and the remaining columns in that table to be horizontally scrollable, in case there are a number of columns that do not fit in the width of the screen. See screenshot:
My initial plan was to use a ListView for the page-level vertical scrolling between tables, and within each table, there is a Row of Columns, where the first column is a static width, and the remaining columns are enclosed within a horizontally scrolling ListView. The error I'm getting from Flutter is not helping me determine what I need to do, but it clearly has to do with having to set bounds on child Widgets.
Error: (Fixed 7/9/19 by wrapping horizontal ListView with a fixed height container and shrinkwrapping the ListView)
The following assertion was thrown during performResize():
Horizontal viewport was given unbounded width.
Viewports expand in the scrolling direction to fill their container.In this case, a horizontal
viewport was given an unlimited amount of horizontal space in which to expand. This situation
typically happens when a scrollable widget is nested inside another scrollable widget.
If this widget is always nested in a scrollable widget there is no need to use a viewport because
there will always be enough horizontal space for the children. In this case, consider using a Row
instead. Otherwise, consider using the "shrinkWrap" property (or a ShrinkWrappingViewport) to size
the width of the viewport to the sum of the widths of its children.
New Error 7/9/19:
The following message was thrown during layout:
A RenderFlex overflowed by 74 pixels on the right.
The overflowing RenderFlex has an orientation of Axis.horizontal.
The edge of the RenderFlex that is overflowing has been marked in the rendering with a yellow and
black striped pattern. This is usually caused by the contents being too big for the RenderFlex.
Consider applying a flex factor (e.g. using an Expanded widget) to force the children of the
RenderFlex to fit within the available space instead of being sized to their natural size.
This is considered an error condition because it indicates that there is content that cannot be
seen. If the content is legitimately bigger than the available space, consider clipping it with a
ClipRect widget before putting it in the flex, or using a scrollable container rather than a Flex,
like a ListView.
The specific RenderFlex in question is:
RenderFlex#9bf67 relayoutBoundary=up5 OVERFLOWING
creator: Row ← RepaintBoundary-[<0>] ← IndexedSemantics ←
NotificationListener ← KeepAlive ← AutomaticKeepAlive ← SliverList ←
SliverPadding ← Viewport ← IgnorePointer-[GlobalKey#74513] ← Semantics ← Listener ← ⋯
parentData: (can use size)
constraints: BoxConstraints(w=404.0, 0.0<=h<=Infinity)
size: Size(404.0, 300.0)
direction: horizontal
mainAxisAlignment: start
mainAxisSize: max
crossAxisAlignment: center
textDirection: ltr
This was the issue I ran into originally before getting side-tracked with the first issue reported; I can't understand why my ListView is not creating a scrollable container.
Code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
home: Scaffold(
appBar: AppBar(
title: Text('My App'),
backgroundColor: Colors.teal[400],
),
body: MyClass(),
),
);
}
}
const double headerCellWidth = 108.0;
const double cellPadding = 8.0;
const double focusedColumnWidth = 185.0;
const double rowHeight = 36.0;
class MyClass extends StatefulWidget {
#override
_MyClassState createState() => _MyClassState();
}
class _MyClassState extends State<MyClass> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return ListView(
padding: EdgeInsets.all(5.0),
children: <Widget>[
Row(
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
color: Colors.grey,
padding: EdgeInsets.all(cellPadding),
width: headerCellWidth,
),
HeaderCell('ABC'),
HeaderCell('123'),
HeaderCell('XYZ'),
],
),
Container(
height: 300.0, // Could compute height with fixed rows and known number of rows in advance
child: ListView(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
children: <Widget>[
Column(
children: <Widget>[
Container(
color: Colors.grey[300],
padding: EdgeInsets.all(cellPadding),
height: rowHeight,
width: focusedColumnWidth,
),
NumberCell('89'),
NumberCell('92'),
NumberCell('91'),
NumberCell('90'),
NumberCell('91'),
NumberCell('89'),
],
),
Column(
children: <Widget>[
Container(
color: Colors.grey[300],
padding: EdgeInsets.all(cellPadding),
height: rowHeight,
width: focusedColumnWidth,
),
NumberCell('89'),
NumberCell('92'),
NumberCell('91'),
NumberCell('90'),
NumberCell('91'),
NumberCell('89'),
],
),
],
),
),
],
),
],
);
}
}
class HeaderCell extends StatelessWidget {
HeaderCell(this.text);
final String text;
#override
Widget build(BuildContext context) {
return Container(
height: rowHeight,
padding: EdgeInsets.all(cellPadding),
width: headerCellWidth,
child: Text(
text,
textAlign: TextAlign.left,
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
);
}
}
class NumberCell extends StatelessWidget {
NumberCell(this.text);
final String text;
#override
Widget build(BuildContext context) {
return Container(
height: rowHeight,
width: focusedColumnWidth,
padding: EdgeInsets.all(cellPadding),
child: Text(
text,
),
);
}
}
Here is a quick example and this would be the result: Video
List<Widget> _buildCells(int count) {
return List.generate(
count,
(index) => Container(
alignment: Alignment.center,
width: 120.0,
height: 60.0,
color: Colors.white,
margin: EdgeInsets.all(4.0),
child: Text("${index + 1}", style: Theme.of(context).textTheme.title),
),
);
}
List<Widget> _buildRows(int count) {
return List.generate(
count,
(index) => Row(
children: _buildCells(10),
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: SingleChildScrollView(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: _buildCells(20),
),
Flexible(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: _buildRows(20),
),
),
)
],
),
),
);
}
So I tried to produce a minimum working bit of code, and ended up with a workable solution (even if all the details aren't ironed out, like the first locked column being of flexible width instead of a fixed width as desired). Hopefully this will help others trying to produce something similar. What's interesting is that the Table construct is needed here, because replacing the TableRow (wrapped by Table) with just a Row causes an overflow error. I would still be interested in understanding why that is since it seems crucial to the layout engine.
#override
Widget build(BuildContext context) {
return ListView(
padding: EdgeInsets.all(5.0),
children: <Widget>[
Table(
children: <TableRow>[
TableRow(
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// first locked column items
],
),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
// table header items
],
),
Row(
children: <Widget>[
// data cells
],
),
Row(
children: <Widget>[
// data cells
],
),
],
),
),
],
),
],
),
],
);
}
If there is not much customization needed, for those needed a fixed header and first column table may also consider to use the horizontal_data_table package:
https://pub.dev/packages/horizontal_data_table
It basically is using the two list view approach.