Text widget not displaying in ListTile flutter - flutter

I want to display a profile image in left section, name and company in middle section (one below other) and reviews and ratings in right section inside a ListTile. I was able to display an image, reviews and ratings correctly, but text is not being displayed. I want to achieve this:
The white space between image and ratings is where I want to show the text (name and company, one below other). Not sure what am I missing here.
Code snippet below:
return new ListTile(
contentPadding: EdgeInsets.all(8.0),
leading: _getProfilePic(pro),
// title: new Text('${pro.fullname}'),
title: new Column(
children: <Widget>[
new Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Text('${pro.fullname}')
],
),
],
),
subtitle: Column(children: <Widget>[
Padding(
padding: EdgeInsets.all(3.0),
),
new Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Text('${pro.company}', style: TextStyle(fontSize: 12.0),
),
],
),
],
),
trailing: new Column(children: <Widget>[
new Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
new StarRating(starCount: 5, rating: pro.rating, color: Colors.amber),
],
),
new Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
new Text('${pro.reviewCount} reviews'),
],
)
],) ,
It seems to me a custom method that return ListView, as below:
Widget buildProList(List pros, BuildContext context) {
List proTiles = new List();
pros.forEach((pro) {
proTiles.add(proTile(pro, context));
});
return new ListView(
children: proTiles
);
}
And this is it's implementation:
ListTile proTile(Pro pro, BuildContext context) {
return new ListTile {
}

You can check the source code of ListTile to check how it is building the tree.
If you read the documentation from ListTile widgets you'll find something like this:
/// The primary content of the list tile.
///
/// Typically a [Text] widget.
final Widget title;
/// Additional content displayed below the title.
///
/// Typically a [Text] widget.
final Widget subtitle;
/// A widget to display after the title.
///
/// Typically an [Icon] widget.
final Widget trailing;
So you have to take in consideration the widgets that you are passing.
Your layout looks to complex, this is an example of how you can build your widget in a very simple way:
new ListTile(
contentPadding: EdgeInsets.all(8.0),
leading: _getProfilePic(pro),
title: new Text('${pro.fullname}'),
subtitle: Text('${pro.company}',
style: TextStyle(fontSize: 12.0),
),
trailing: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new StarRating(starCount: 5, rating: pro.rating, color: Colors.amber),
new Text('${pro.reviewCount} reviews'),
],
),
),
Another solution without using ListTile:
return Row(
children: <Widget>[
_getProfilePic(pro),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'${pro.fullname}',
overflow: TextOverflow.ellipsis,
),
new Text(
'${pro.company}',
style: TextStyle(fontSize: 12.0),
),
],
),
),
new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new StarRating(starCount: 5, rating: pro.rating, color: Colors.amber)
new Text('${pro.reviewCount} reviews'),
],
)
],
);
Note: Don't forget to check the parent constraints of your child widget

Related

What widget should I use for center text and left-aside button

I am making layout for flutter application
What I want to do is
-----------------------
|[i] [text] |
| |
Icon should be the left (padding 5px)
And text should be the center of screen.
At first I should use the Column
However my layout is not the same proportion
It might be simple though , how can I make it??
Stack() is one of the many options that you can use. Something like this:
Stack(
children:<Widget>[
Padding(
padding: EdgeInsets.only(left: 5),
child: Icon(Icons.info),
),
Align(
alignment: Alignment.topCenter,
child: Text("I'm on the top and centered."),
),
],
),
One way you can do this is something like this..
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding: EdgeInsets.all(5),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(Icons.info),
Text('text'),
Opacity(opacity: 0, child: Icon(Icons.info)),
],
),
),
Padding(
padding: EdgeInsets.all(5),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(Icons.info),
Text('second text'),
Opacity(opacity: 0, child: Icon(Icons.info)),
],
),
),
],
);
}
Result:
I might be late, but I want this answer to be there, if some one would find it better for the development purposes in future time.
We can make a reusable widget, which we can use it inside the main widget. The widget will accept text, and icon to be passed when called
// IconData is the data type for the icons
Widget myWidget(String text, IconData icon) => Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
// this will be used a left-padding param
SizedBox(width: 20.0),
// using it here
Icon(icon, size: 28.0, color: Colors.greenAccent),
SizedBox(width: 5.0),
// this will take the remaining space, and then center the child
Expanded(child: Center(child: Text(text)))
]
);
To use in the main Widget, just do like this:
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// calling our widget here
myWidget('FirstText', Icons.alarm),
SizedBox(height: 20.0), // this is used as a top margin
myWidget('SecondText', Icons.notifications)
]
)
If you wanna check out the sources which I used, please see:
Expanded class
SizedBox class
The result you will get is this:
This was an answer I gave a while ago for this same issue, but the other situation was vertical (a Column) instead of horizontal (a Row). Just swap the Row and Columns out for a Column and Rows in this example and you'll get the idea.
My code has grey added in order to show the difference between the two approaches.
A Stack will work, but it's overkill for this, this kind of problem is part of why we have Expandeds and Flexibles. The trick is to use three Flexibles (2 Expandeds and a Spacer). Put the Spacer on top. It and the bottom Expanded must have the same flex value in order to center the middle Expanded.
import 'package:flutter/material.dart';
class CenteringOneItemWithAnotherItemInTheColumn extends StatelessWidget {
const CenteringOneItemWithAnotherItemInTheColumn({
Key key,
}) : super(
key: key,
);
/// Adjust these values as needed
final int sameFlexValueTopAndBottom = 40; // 40%
final int middleFlexValue = 20; // 20%
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Column Alignment Question'),
),
body: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Spacer(),
const Text(
'Cent',
style: TextStyle(
fontSize: 64,
),
),
const Spacer(),
const Text(
'Bot',
style: TextStyle(
fontSize: 64,
),
),
],
),
Column(
children: <Widget>[
/// The key is to have the Spacer and the bottom Expanded
/// use the same value for flex. That will cause the middle
/// child of the Column to be centered vertically.
Expanded(
flex: sameFlexValueTopAndBottom,
child: Container(
width: 100,
color: Colors.grey[300],
),
),
Expanded(
flex: middleFlexValue,
child: const Align(
alignment: Alignment.center,
child: Text(
'Cent',
style: TextStyle(
fontSize: 64,
),
),
),
),
Expanded(
flex: sameFlexValueTopAndBottom,
child: Container(
color: Colors.grey[300],
child: const Align(
alignment: Alignment.bottomCenter,
child: Text(
'Bot',
style: TextStyle(
fontSize: 64,
),
),
),
),
),
],
),
],
),
);
}
}

How to fill contents inside wrap widget?

I want to move widgets to the new line automatically if it's overflow and Wrap widget is a good way for this.
so I have some wrap widgets which have width based on text length and some icons like:
Current actual:
I want to align 2 icons on the left and right side of the parent.
but as you can see the red-colored area of Row, I don't know how to make Row width match to the parent when Text widget has longer than Row (in the above case of the attached image, something?)
This is what I expect:
and my current code is:
Wrap(
direction: Axis.horizontal,
crossAxisAlignment: WrapCrossAlignment.start,
children: [
Container(
child: Column(
children: [
Text(
"hoge",
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.edit),
Icon(Icons.more_vert),
],
)
],
),
),
Container(
child: Column(
children: [
Text(
"too long text...............",
),
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Icon(Icons.edit),
Icon(Icons.more_vert),
],
)
],
),
),
Container(
child: Column(
children: [
Text(
"hoge",
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.edit),
Icon(Icons.more_vert),
],
)
],
),
),
],
),
How to achieve this?
IntrinsicWidth(
child: Column(
children: [
Text(
"too long text...............",
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Icon(Icons.edit),
Icon(Icons.more_vert),
],
)
],
),
),
Wrap your long text Column with IntrinsicWidth instead of normal Container Widget.moreover, remove the mainAxisSize constraint on the Row widget to make it's width same as Text widget.
https://api.flutter.dev/flutter/widgets/IntrinsicWidth-class.html
I think this is what you're looking for List of Containers side by side
I made it dynamic so that you can add new items if you want base on the list of Item.
class Item {
String text;
IconData icon1;
IconData icon2;
Color color;
Item({ this.text, this.icon1, this.icon2,this.color,});
}
We can make this dynamic by creating a List of Item
final List<Item> item = [
Item(
text: 'Item 3',
icon1: Icons.edit,
icon2: Icons.more_vert,
color: Colors.blue,
),
Item(
text: 'Item 2 This text is too long for the screen width..... screen width.....screen width.....screen width.....',
icon1: Icons.edit,
icon2: Icons.more_vert,
color: Colors.greenAccent,
),
Item(
text: 'Item 3',
icon1: Icons.edit,
icon2: Icons.more_vert,
color: Colors.amberAccent[100],
),
];
You might also want to look at Wrap Class
Wrap(
spacing: 8.0, // gap between adjacent chips
runSpacing: 4.0, // gap between lines
children: item.map((Item) {
return GestureDetector(
child: Container(
decoration: BoxDecoration(
color: Item.color,
),
margin: const EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(Item.text),
Wrap(
children: <Widget>[
Icon(Item.icon1),
Icon(Item.icon2),
],
)
],
),
),
onTap: () => {},
);
}).toList(),
),

Header image to show

I'm trying to get a header image to show on a page of an app but it's not showing up and the _header seems to be greyed out in my code. I'm missing something I guess that I'm unsure of. Edit: I need the header to show above the rows of content in the build.
Widget _header() {
return new Container(
child: new Row(
children:<Widget>[
new Column(
children: <Widget>[
Image.asset(
'assets/classes-Image.png',
),
],
),
],
),
);
}
Extra code below:
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: const Text('Learn How to Paint'),
backgroundColor: Color(0xFF202945),
),
body: new Container(
child: ListView(
shrinkWrap: true,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Column(
children: <Widget>[
Row(
children: <Widget>[
new Padding(
padding: const EdgeInsets.only(
left: 20.0,
),
),
Image.asset(
'assets/Profile-Photo.png',
),
new Padding(
padding: const EdgeInsets.only(
right: 20.0,
),
),
Text(
'Katherine G.',
),
],
),
],
),
```
You can achieve this by placing your header widget right before the Row widget.
The header is not showing because you didn't add it in the ListView.
I hope this solves your issue.
You need to be calling _header() from somewhere in your build function and give the result as a child to another widget. It being grayed out probably means you're not calling it.

How To Make A Widget Just Stick To Bottom Of Page

I am trying to build a view as in the image below.
The tweet your reply is just stack at the bottom while the other stuff are scrollable.
I've been banging my head on how to achieve this for a couple of hours.
Exactly;y like in the image below. There are four sections:
The post (tweet)
The row of icons
The comments (which scrolls)
The tweet your reply which is static
The solution would be to use the Align Widget. So in your Stack you would put as the last element in the stack:
Align(
alignment: Alignment.bottomCenter,
child: // your widget would go here
),
I'm judging by your question that you have figured out how to do all of the other parts, and was just wondering about the bottom part. You can use Align to align things in other ways as well (such as topCenter, bottomLeft, etc). Hope this helps, and if so please up vote and accept as answer and if not leave a comment below.
Edit:
I wouldn't use a Stack. I would wrap the entire widget tree in a Column, and put the post in a Expanded Widget with a flex factor of 1, and a Row of Icons below it. Then put a ListView in an Expanded Widget with a flex of 4 (you can experiment with values). And lastly in the Column I would add you "Tweet you reply" Widget.
Simple layout code to give you an idea of how to implement it:
Column(
children: <Widget>[
Expanded(
child: ListView(
shrinkWrap: true,
children: <Widget>[
//your post
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
// your icons
],
),
//your comments
],
),
),
Align(
alignment: Alignment.bottomCenter,
child: // you textField,
),
],
)
Try this
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(50),
child: Center(
child: Text(
"A POST"
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Icon(Icons.details),
Icon(Icons.print),
Icon(Icons.translate),
Icon(Icons.map)
],
),
Expanded(
child: ListView(
children: List.generate(10, (index) => ListTile(title: Text("Comment $index"),)),
),
)
],
),
),
TextField(
decoration: InputDecoration(
labelText: "Tweet your reply"
),
)
],
),
),
);
}
}
The output:
If you want the post to scroll with it, this should help
import 'package:flutter/material.dart';
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(50),
child: Center(
child: Text(
"A POST"
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Icon(Icons.details),
Icon(Icons.print),
Icon(Icons.translate),
Icon(Icons.map)
],
),
Column(
children: List.generate(10, (index) => ListTile(title: Text("Comment $index"),)),
)
],
),
),
),
TextField(
decoration: InputDecoration(
labelText: "Tweet your reply"
),
)
],
),
),
);
}
}

How to make a row having icon and text tappable?

I have 2 questions related :
I have nested function BuildButtonColumn which takes an icon
and text below it and I want to make it tappable. I know
GestureDetector has onTap property, but how do I use that in the
function BuildButtonColumn ?
Column buildButtonColumn(IconData icon, String label) {
Color color = Theme
.of(context)
.primaryColor;
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.all(10.0),
),
Icon(icon, color: color),
Container(
margin: const EdgeInsets.only(top: 8.0),
child: Text(
label,
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.bold,
color: Colors.black,
)
),
)
],
);
}
Widget buttonSection = Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
buildButtonColumn(Icons.message, 'Message'),
buildButtonColumn(Icons.videocam, 'Request Video')
],
),
);
I took button layout reference from here.
And this is the UI wherein I need to open specific screen on each icon or text tap.
I also want to show a vertical divider between them. I followed
this SO post, but it didn't work out for me or I might have
missed something there to implement it.
Instead return Column you can write:
return GestureDetector(
onTap: (){ ... },
child: Column(),
)
Regarding divider - VerticalDivider() is totally fine for me
Widget buttonSection = Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
buildButtonColumn(Icons.message, 'Message'),
VerticalDivider(color: Colors.black,),
buildButtonColumn(Icons.videocam, 'Request Video')
],
),
);
It has to work