I'm trying to build a ListView, where the tiles look like this:
However, I'm facing some issues here.
So the item layout is
#override
Widget build(BuildContext context) {
return new GestureDetector(
onTap: _onTap,
child: new Card(
elevation: 1.0,
color: Colors.white,
margin: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 15.0),
child: new Container(
child: new Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
margin: const EdgeInsets.only(right: 15.0),
width: 100.0,
height: 130.0,
padding: const EdgeInsets.symmetric(
vertical: 10.0, horizontal: 5.0),
decoration: new BoxDecoration(
shape: BoxShape.rectangle,
image: new DecorationImage(
fit: BoxFit.cover,
image: new NetworkImage(
"https://image.tmdb.org/t/p/w500" +
widget.movie.posterPath
)
)
),
),
new Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Expanded(
flex: 0,
child: new Container(
margin: const EdgeInsets.only(
top: 12.0, bottom: 10.0),
child: new Text(widget.movie.title,
style: new TextStyle(
fontSize: 18.0,
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
),
new Expanded(
flex: 0,
child: new Text(
widget.movie.voteAverage.toString(),
style: new TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
color: Colors.grey[600]
),
),
),
],
),
new Container(
child: new Text(widget.movie.overview,
softWrap: true,
overflow: TextOverflow.ellipsis,
maxLines: 3,
),
),
new Container(
margin: const EdgeInsets.only(top: 5.0),
child: new Row(
children: <Widget>[
new Text("Released"),
new Container(
margin: const EdgeInsets.only(left: 5.0),
child: new Text(widget.movie.releaseDate)
),
],
),
),
new Container(
margin: const EdgeInsets.only(top: 5.0),
child: new Row(
children: <Widget>[
new Text("Rating"),
new Container(
margin: const EdgeInsets.only(left: 5.0),
child: new Text(widget.movie.voteAverage.toString())
),
],
),
),
],
)
],
),
),
),
);
}
The layout hierarchy, as you can see in the image above, is
Row -> Image, Column -> (Row -> (Title, Rating)), Description, Text,
Text
First Issue
The first issue is that I'm unable to align the Rating to the right within the Title, Rating row. So I want the title to be left aligned, and rating to be right aligned. For this, I tried to give a flex rating to both widgets, but as soon as I do that, both disappear. The only way I can think of is to give the Title a width, but that's a very hacky way and will break on most devices.
Second Issue
I want the Description to fit within the bounds of the Card. However, unless I define a specific width to the Container for Description, I'm unable to constrain it within the bounds of the screen. I tried encasing it within an Expanded, Flex and Flexible with various flex values, but no luck. I tried to use the softWrap property of Text widget, but again no luck. As soon as I wrap the Text in any of those widgets, it disappears. In the above code I've wrapped the Text in a Container, and set a width to it. This works, but again, it's very hacky, and will look different on different device, plus will break on a few.
Any help on these issues would be great.
After a lot of trial and error, I finally managed to get what I wanted.
My layout is like this:
#override
Widget build(BuildContext context) {
return new GestureDetector(
onTap: _onTap,
child: new Card(
elevation: 1.0,
color: Colors.white,
margin: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 14.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
margin: const EdgeInsets.only(right: 15.0),
width: 100.0,
height: 150.0,
child: new Image.network(
"https://image.tmdb.org/t/p/w500" +
widget.movie.posterPath),
),
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Row(
children: <Widget>[
new Expanded(
child: new Container(
margin: const EdgeInsets.only(
top: 12.0, bottom: 10.0),
child: new Text(widget.movie.title,
style: new TextStyle(
fontSize: 18.0,
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
),
new Container(
margin: const EdgeInsets.only(right: 10.0),
child: new Text(
widget.movie.voteAverage.toString(),
style: new TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
color: Colors.grey[600]
),
),
),
],
),
new Container(
margin: const EdgeInsets.only(right: 10.0),
child: new Text(widget.movie.overview,
style: new TextStyle(
fontSize: 16.0,
),
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
),
new Container(
margin: const EdgeInsets.only(top: 10.0),
child: new Row(
children: <Widget>[
new Text("RELEASED",
style: new TextStyle(
color: Colors.grey[500],
fontSize: 11.0,
),
),
new Container(
margin: const EdgeInsets.only(left: 5.0),
child: new Text(widget.movie.releaseDate)
),
],
),
),
],
),
),
],
),
),
);
}
What I had to do was make the second child of my top level row an Expanded widget. So as you can see in the code, I put my column (after the image) within an Expanded.
The problem that was happening before was that Row has infinite bounds, so making my text expanded within a row's column was not making any difference to it.
However, when I put the entire column into an expanded, it was bound by the screen width. That is what needs to be done.
The final output, with the above code, looks like this.
Here is the solution of your both the problem.
1) You just have to assign mainAxisAlighment.spaceBetween.
And you will good to go.
Below is the sample code which is solving your both the problems.
new Column(
children: <Widget>[
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Container(
margin: const EdgeInsets.only(
top: 12.0, bottom: 10.0, left: 10.0),
child: new Text(
"Avengers: Infinity war",
style: new TextStyle(
fontSize: 18.0,
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
new Container(
margin: const EdgeInsets.all(10.0),
child: new Text(
"8.6",
style: new TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
color: Colors.grey[600]),
),
)
],
),
new Container(
margin: const EdgeInsets.only(left: 10.0, right: 10.0),
child: new Text(
"Iron Man, Thor, the Hulk and the rest of the Avengers unite to battle their most powerful enemy yet -- the evil Thanos. On a mission to collect all six Infinity Stones, Thanos plans to use the artifacts to inflict his twisted will on reality.",
softWrap: true,
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
)
],
)
Related
I have a widget layout like this:
And here's the code of it:
Column(
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.lightbulb_outline),
SizedBox(
width: 4,
),
Text(
'Something something something',
style: kTextRegularW500,
),
],
),
Padding(
padding: const EdgeInsets.only(top: 13.0),
child: Container(
padding: EdgeInsets.symmetric(
vertical: 17,
),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(16),
),
child: Center(
child: Text(
'Next',
style: TextStyle(
color: Colors.white,
),
),
),
),
),
],
)
Question:
How to make the "button" widget (Padding, the second widget in the Column) the same width as the Row(the first widget of the Column) above it?
What I have tried:
I simply added a fixed width to the Container that render as the button, and here's the result:
Here's the code:(I only append the Container(button) part of it)
Container(
width: 300,
padding: EdgeInsets.symmetric(
vertical: 17,
)
Even adding a fixed width to Container achieve what I want, but it's just fixed for this particular case... if the text above the button become longer, I will be back to where I was facing at the first place...
So, the only solution I can come up with is to find a way to make the Container the same width as the Row above it, or obtaining the size from a sibling widget then apply it, but I don't know how even after hours searching...
Or if you have any other way to make the button(Container) the same size as the Row, you are welcomed to share.
wrap your column with IntrinsicWidth
IntrinsicWidth(
child: Column(
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.lightbulb_outline),
SizedBox(
width: 4,
),
Text(
'Something something something something',
// style: kTextRegularW500,
),
],
),
Padding(
padding: const EdgeInsets.only(top: 13.0),
child: Container(
padding: EdgeInsets.symmetric(
vertical: 17,
),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(16),
),
child: Center(
child: Text(
'Next',
style: TextStyle(
color: Colors.white,
),
),
),
),
),
],
),
)
output:
I have a Row widget, which has many containers with different heights depending on their content. I want to have an equal height of them all. How can I achieve this without hardcoding their values?
This is something I have.
But I want the first card to take the height of the row automatically. So that both cards would be of the same height. How can I achieve this?
This is the code for Card Container:
Widget build(BuildContext context) {
final statusMap = statusOptionView();
return Container(
width: 200,
margin: EdgeInsets.only(right: 20.0),
child: Stack(
children: <Widget>[
Container(
padding: EdgeInsets.only(
left: 20.0, right: 20.0, top: 20.0, bottom: 50.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20.0)),
color: Color(0xFFF97F8B),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
Icon(
Icons.access_time,
color: Colors.white,
),
SizedBox(width: 4.0),
Text(
event.startTime,
style: TextStyle(
color: Colors.white,
),
)
],
),
SizedBox(
height: 20.0,
),
Text(
event.title,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 20.0,
color: Colors.white,
),
maxLines: 2,
),
SizedBox(
height: 20.0,
),
Row(
children: <Widget>[
Icon(
Icons.location_on,
color: Colors.white,
),
SizedBox(
width: 4.0,
),
Expanded(
child: Text(
event.venue,
style: TextStyle(
color: Colors.white,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
)
],
),
],
),
),
Positioned(
bottom: 0.0,
right: 0.0,
left: 0.0,
child: GestureDetector(
onTap: () => Navigator.push(context, MaterialPageRoute(
builder: (BuildContext context) => EventDetailsScreen(event: event, status: status))),
child: Container(
padding: EdgeInsets.symmetric(vertical: 8.0),
decoration: BoxDecoration(
color: Colors.purple,
borderRadius: BorderRadius.circular(30.0)),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
statusMap['icon'],
color: Colors.white,
size: 16.0,
),
SizedBox(
width: 10.0,
),
Text(
statusMap['value'],
style: TextStyle(
color: Colors.white,
),
),
],
),
),
),
)
],
),
);
While it is wrapped inside a Row widget, just like this:
Row(
children: <Widget>[...events.map((event) => EventCard(event: event)).toList()],
)
Use IntrinsicHeight as parent of Row that contains Card
You can use CrossAxisAlignment.stretch to make all children of a Row/Column use the same height/width.
/// Require the children to fill the cross axis.
///
/// This causes the constraints passed to the children to be tight in the
/// cross axis.
stretch,
Check out https://codepen.io/kuhnroyal/pen/wvGormg
In your case, row is a child of column and column gives full available height to its children so row as a child of the column, take full available height so to tell column that only give required height to its children try to give MainAxisSize.min property to Column. I am not sure it works or not but you can try.
Row(
mainAxisAlignment : MainAxisAlignment.spaceEvenly,
.....)
or try wrapping every widget with expanded.
Hoping that it works
I want to align my transaction title and date to the left but when I give the parent container the full width of the row i.e. double.infinity, the following exception is thrown "BoxConstraints forces an infinite width". What could be the possible reason?
body: new Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
new Card(child: new Text("CHART!")),
new Column(
children: [
...transactions.map((transaction) {
return new Card(
child: new Row(
children: [
new Container(
padding: EdgeInsets.all(10),
decoration: new BoxDecoration(
border: Border.all(
color: Colors.purple,
width: 2,
),
),
margin: EdgeInsets.symmetric(
vertical: 10,
horizontal: 15,
),
child: new Text(
transaction.amount.toString(),
style: new TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
color: Colors.purple),
),
),
new Column(
children: [
new Container(
width: double.infinity,
child: new Text(
transaction.title,
style: new TextStyle(
fontWeight: FontWeight.bold, fontSize: 17),
),
),
new Container(
child: new Text(
transaction.date.toString(),
style: new TextStyle(color: Colors.grey),
),
),
],
)
],
),
);
})
],);
The Row() widget does not have a width property, meaning that you should put the Row() inside another Container(), so that the row knows what its constraints are, like this:
new Row(
children: [
new Container(
padding: EdgeInsets.all(10),
decoration: new BoxDecoration(
border: Border.all(
color: Colors.purple,
width: 2,
),
),
margin: EdgeInsets.symmetric(
vertical: 10,
horizontal: 15,
),
child: new Text(
transaction.amount.toString(),
style: new TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
color: Colors.purple),
),
),
new Column(
children: [
new Container(
width: MediaQuery.of(context).size.width,,
child: new Text(
transaction.title,
style: new TextStyle(
fontWeight: FontWeight.bold, fontSize: 17),
),
),
new Container(
child: new Text(
transaction.date.toString(),
style: new TextStyle(color: Colors.grey),
),
),
],
)
],
Note: the new keyword is optional. Furthermore, setting a width to infinity will only cause problems, since it will always go out of the screen, creating an overflow.
The problem is You are setting stretch for crossAxisAlignment, which gives infinite width to the column. You can provide constraint to the Container, through width property by setting
width: MediaQuery.of(context).size.width
This should work.
i am trying to accomplish layout where components are overlay in flutter but im having problem.
here is the code that i have so far
import 'package:flutter/material.dart';
class FirstFragment extends StatelessWidget {
_getSizes() {
}
_getPositions(){
}
#override
Widget build(BuildContext context) {
return new Container(
constraints: new BoxConstraints.expand(
height: 200.0,
),
padding: new EdgeInsets.only(left: 0.0, bottom: 8.0, right: 16.0),
decoration: new BoxDecoration(
color: Colors.blue,
),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
textDirection: TextDirection.rtl,
children: [
Text(
'0.00',
style: TextStyle(
color: Colors.white,
fontSize: 50.0,
fontWeight: FontWeight.bold
),
),
Text(
'Current Balance',
style: TextStyle(
color: Colors.white,
fontSize: 26.0,
fontWeight: FontWeight.bold
),
),
new Card(
child: new Column(
children: <Widget>[
new Image.network('https://i.ytimg.com/vi/fq4N0hgOWzU/maxresdefault.jpg'),
new Padding(
padding: new EdgeInsets.all(7.0),
child: new Row(
children: <Widget>[
new Padding(
padding: new EdgeInsets.all(7.0),
child: new Icon(Icons.thumb_up),
),
new Padding(
padding: new EdgeInsets.all(7.0),
child: new Text('Like',style: new TextStyle(fontSize: 18.0),),
),
new Padding(
padding: new EdgeInsets.all(7.0),
child: new Icon(Icons.comment),
),
new Padding(
padding: new EdgeInsets.all(7.0),
child: new Text('Comments',style: new TextStyle(fontSize: 18.0)),
)
],
)
)
],
),
)
],
)
);
}
}
when you run the code, you will notice that the card view shrink and doesnt overlay the container. i am looking to do the same as the image below:
notice how the card view with title of Summary is overlay the blue background and then there are other card views below summary card view.
i am getting the following from my code. the card view doesnt overlay like the image above. can someone help? thanks in advance
NOTE: it will be great if anyone can make my card view look like the one in Summary card view in the image above. the one in my code i copied from somewebiste with the goal of making it look like the image above
Remove following from your Container
constraints: new BoxConstraints.expand(
height: 200.0,
)
Add mainAxisSize: MainAxisSize.min to your Column.
new Column(
mainAxisSize: MainAxisSize.min, // add this
crossAxisAlignment: CrossAxisAlignment.center,
children: ...
)
Full solution:
class FirstFragment extends StatelessWidget {
_getSizes() {}
_getPositions() {}
#override
Widget build(BuildContext context) {
return new Container(
padding: new EdgeInsets.only(left: 0.0, bottom: 8.0, right: 16.0),
decoration: new BoxDecoration(color: Colors.blue),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Text(
'0.00',
style: TextStyle(color: Colors.white, fontSize: 50.0, fontWeight: FontWeight.bold),
),
Text(
'Current Balance',
style: TextStyle(color: Colors.white, fontSize: 26.0, fontWeight: FontWeight.bold),
),
new Card(
child: new Column(
children: <Widget>[
new Image.network('https://i.ytimg.com/vi/fq4N0hgOWzU/maxresdefault.jpg'),
new Padding(
padding: new EdgeInsets.all(7.0),
child: new Row(
children: <Widget>[
new Padding(
padding: new EdgeInsets.all(7.0),
child: new Icon(Icons.thumb_up),
),
new Padding(
padding: new EdgeInsets.all(7.0),
child: new Text(
'Like',
style: new TextStyle(fontSize: 18.0),
),
),
new Padding(
padding: new EdgeInsets.all(7.0),
child: new Icon(Icons.comment),
),
new Padding(
padding: new EdgeInsets.all(7.0),
child: new Text('Comments', style: new TextStyle(fontSize: 18.0)),
)
],
))
],
),
)
],
),
);
}
}
UI Layout
If the purple area is inside an Expanded widget, how would I go about to position the button? I've implemented that UI by setting a fixed height to the purple container but haven't been able to understand how to achieve the same effect if the height is variable, depending on the content.
I was able to get close by using Stack and Positioned widgets but then the button is not really clickable. If anyone can give me a general idea on how to achieve the desired goal I would be thankful.
Here's my attempt (demo case)
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
flex: 1,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Colors.redAccent,
),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Stack(
children: <Widget> [
Padding(
padding: const EdgeInsets.only(bottom: 40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Icon(
Icons.book,
color: Colors.white,
size: 40.0
),
Container(
width: 90.0,
child: new Divider(color: Colors.white),
),
Text(
"Some random text -",
style: TextStyle(color: Colors.white, fontSize: 25.0),
),
Padding(
padding: const EdgeInsets.only(top: 8.0, right: 70.0),
child: Row(
children: <Widget>[
Flexible(
child: Text(
'More random text that can vary a lot!',
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Row(
children: <Widget>[
Text(
'Random text ',
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
fontWeight: FontWeight.bold,
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Row(
children: <Widget>[
Text(
'Random',
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
),
Positioned(
bottom: 0.0,
left: MediaQuery.of(context).size.width - 100.0,
child: FractionalTranslation(
translation: const Offset(0.0, 0.8),
child: FloatingActionButton(
backgroundColor: Colors.white,
foregroundColor: Colors.redAccent,
child: new Icon(
Icons.map
),
onPressed: () {
},
),
),
),
]
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 8.0, left: 8.0),
child: Row(
children: <Widget>[
Flexible(
child: Text(
"Random text",
style: new TextStyle(
fontFamily: 'Raleway',
fontSize: 16.0,
color: Colors.black38
)
),
),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Random text - long text",
style: new TextStyle(
fontFamily: 'Raleway',
fontSize: 18.0
)
),
),
],
)
],
)
),
),
],
);
Explaining what I described in the comments:
You can use the FractionalTranslation widget to shift your FAB half way down.
FractionalTranslation(translation: Offset(0, .5), child: FloatingActionButton(...))
This requires you to have it positioned at the bottom of the purple area (referring to your screenshot) beforehand, but I assume that you have that figured out.