How to create facebook like comment structure in flutter? - flutter

I am trying to construct comment section in a project I am working on. And I want it the way facebook have done it. I have taken care of almost everything right now but how can I populate a field right below the original comment and create another comment field which will be typed when pressed reply?
Please have a look at the code and help me with this.
class MyHomePageState extends State<MyHomePage> {
Widget postComment(String time, String postComment, String profileName,
String profileImage, int likeCount) {
return Padding(
padding: EdgeInsets.only(left: 16.0, right: 16.0, top: 16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
CircleAvatar(maxRadius: 16, child: Image.asset(profileImage)),
SizedBox(
width: 16.0,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
color: Hexcolor('#E9F1FE'),
borderRadius: BorderRadius.circular(6.0),
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
profileName,
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
postComment,
style: TextStyle(fontSize: 16.0),
)
],
),
),
),
SizedBox(
height: 12.0,
),
Row(
children: [
Text(time, style: TextStyle(fontWeight: FontWeight.w600)),
SizedBox(
width: MediaQuery.of(context).size.width * 0.1,
),
Text('Like', style: TextStyle(fontWeight: FontWeight.w600)),
SizedBox(
width: MediaQuery.of(context).size.width * 0.1,
),
InkWell(
onTap: () {},
child: Text(
'Reply',
style: TextStyle(fontWeight: FontWeight.w600),
),
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.24,
),
InkWell(
onTap: () {
// _incrementCommentLikeCount();
},
child: Text('$likeCount')),
SizedBox(
width: MediaQuery.of(context).size.width * 0.02,
),
SvgPicture.asset('assets/like.svg')
],
)
],
)
],
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: [
///Just calling the widget for sake of example
postComment(
'2h', 'This is a comment', 'Unknown Name', 'assets/img1.png', 10)
],
));
}
}
Here is the output:

If you're looking for ways on how you can update a ListView, you can populate the ListView with a List of Objects i.e. List<Comment> _comments;.
As an example, you can create a Comment model
class Comment {
String commentId;
String userId;
String comment;
Timestamp timestamp;
Comment(
{required this.id,
required this.sender,
required this.comment,
required this.timestamp});
...
Then use the List to populate ListView.builder with data.
ListView.builder(
itemCount: _comments.length,
itemBuilder: (BuildContext context, int index) {
// Return a Widget for the comments
return Container(...);
}
)
You can then access Comment objects inside List<Comment> using the index provided by ListView.builder()
i.e. Text('${_comments[index].comment}')
To add new comments on the List, you can just add new Comment objects on the List.
_comments.add(Comment(
commentId: generatedCommentId,
userId: senderUserId,
comment: senderMessage,
timestamp: DateTime.now(),
));

Related

how can i get individual data variables into another page after building a function in flutter?

how can i get individual data variables into another page after building a function that displays them all
This is the calling of the function which i will be using php for later to query list of them from the database.
buildOrderItem('images/shoe.jpg', "Men's Italian Shoe", 150.00),
buildOrderItem('images/suit.jpg', 'FloTextile Suit', 450.00),
buildOrderItem('images/heels.jpg', "Women's Heel", 200.00),
and this is the function
Container buildOrderItem(imagelink, productName, price) {
return Container(
child: InkWell(
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new ProductPage()));
},
child: Container(
margin: EdgeInsets.only(left: 20, right: 20, top: 10, bottom: 10),
decoration: BoxDecoration(
color: Colors.white, borderRadius: BorderRadius.circular(10)),
child: Column(
children: [
Container(
child: Image.asset(
imagelink,
width: 250,
height: 150,
fit: BoxFit.scaleDown,
),
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
padding: EdgeInsets.all(20),
child: Text(
productName,
style: TextStyle(fontWeight: FontWeight.bold),
),
),
Container(
padding: EdgeInsets.all(20),
child: Text(
'N' + price.toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.deepOrange),
),
)
],
),
),
],
),
),
),
);
from the ontap, how can i pass the data variables (imagelink, productName, price) from the particular product i click into the next screen...
onTap:(){
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new ProductPage()));
},
i tried sending the variables as parameters into the routes but I'm receiving null.
kindly help, thanks
buildOrderItem(
'assets/images/researcher.png',
"mans's Heel",
200.00,
() {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) =>
ProductPage('mans\'s Heel'),
),
);
},
),
then on this section do this
Widget buildOrderItem(imagelink, productName, price, Function ontap) {
return Container(
child: InkWell(
onTap: ontap,
child: Container(
margin: EdgeInsets.only(left: 20, right: 20, top: 10, bottom: 10),
decoration: BoxDecoration(
color: Colors.white, borderRadius: BorderRadius.circular(10)),
child: Column(
children: [
Container(
child: Image.asset(
imagelink,
width: 250,
height: 150,
fit: BoxFit.scaleDown,
),
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
padding: EdgeInsets.all(20),
child: Text(
productName,
style: TextStyle(fontWeight: FontWeight.bold),
),
),
Container(
padding: EdgeInsets.all(20),
child: Text(
'N' + price.toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.deepOrange),
),
)
],
),
),
],
),
),
),
);
}
Just create constructor for your ProductPage and pass your variables to there
class ProductPage extends StatelessWidget { /* Or StatefulWidget and then in the State use these variable like widget.someVariable*/
ProductPage({
required this.someVariable,
required this.someVariable2,
required this.someVariable3,
Key? key,
}) : super(key: key);
final String someVariable;
final String someVariable2;
final double someVariable3;
//...
}
To pass these variables:
//...
ProductPage(
someVariable: 'Some value',
someVariable2: 'Some value',
someVariable3: 101.12,
)
//...
You should also create a class Product that will contain these variables (better with final keyword) and then pass this class
If you want to have your product in a few pages, you should use InheritedWidget or provider package (it actually uses InheritedWidget and it is just easyer and more convinient)

Flutter UI List Item

I am using the below code but not able to achieve the desired result, I am new to the flutter world so let me know where to improve to get the desired result. Here is the source code of what I have done.
return Expanded(
child: GridView.builder(
controller: _scrollController,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: albumList.length,
itemBuilder: (BuildContext context, int index) {
return buildRow(index);
},
),
);
Widget buildRow(int index) {
return AlbumTile(
index: index,
albumList: albumList,
deleteAlbum: _deleteAlbum,
);
}
This the Album Tile
class AlbumTile extends StatelessWidget {
AlbumTile(
{Key key,
#required this.index,
#required this.albumList,
#required this.deleteAlbum})
: super(key: key);
final int index;
final List<Album> albumList;
final Function deleteAlbum;
#override
build(BuildContext context) {
String thumb;
if (albumList.elementAt(index).thumbUrl != "") {
thumb = WEBSERVICE_IMAGES +
albumList.elementAt(index).userId.toString() +
'/' +
albumList.elementAt(index).id.toString() +
'/' +
albumList.elementAt(index).thumbUrl;
} else {
thumb = "https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823__340.jpg";
}
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
new AlbumPage(tabIndex: index, albumList: albumList),
),
);
},
child: Container(
// height of the card which contains full item
height: MediaQuery.of(context).size.height * 0.4,
width: MediaQuery.of(context).size.width * 0.28,
// this is the background image code
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
// url is my own public image url
image: NetworkImage(thumb),
),
borderRadius: BorderRadius.circular(12.0)),
// this is the item which is at the bottom
child: Align(
// aligment is required for this
alignment: Alignment.bottomLeft,
// items height should be there, else it will take whole height
// of the parent container
child: Container(
padding: EdgeInsets.only(left: 10.0, right: 0.0),
height: MediaQuery.of(context).size.height * 0.1,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Text() using hard coded text right now
Text(albumList.elementAt(index).name,
style: TextStyle(
fontSize: 18.5,
color: Colors.white,
fontWeight: FontWeight.w500)),
SizedBox(height: 3.0),
Text(albumList.elementAt(index).photos.toString() +' photos',
style: TextStyle(
fontSize: 12.5,
color: Colors.white,
fontWeight: FontWeight.w500))
],
),
),
// pop-up item
PopupMenuButton(
icon: Icon(Icons.more_vert, color: Colors.white),
itemBuilder: (_) => <PopupMenuItem<String>>[
new PopupMenuItem<String>(
child: Row(
children: <Widget>[
Icon(Icons.delete),
Text(
'Delete Album',
),
],
),
value: 'Delete',
),
],
onSelected: (value) {
deleteAlbum(albumList.elementAt(index).id, index);
},
),
],
),
),
),
),
);
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
new AlbumPage(tabIndex: index, albumList: albumList),
),
);
},
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Stack(
fit: StackFit.loose,
children: <Widget>[
ClipRRect(
borderRadius: new BorderRadius.circular(8.0),
child: FadeInImage.assetNetwork(
height: 1000,
placeholder: kPlaceHolderImage,
image: thumb,
fit: BoxFit.cover,
),
),
Align(
alignment: Alignment.bottomLeft,
child: Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(8, 0, 0, 0),
child: Text(
albumList.elementAt(index).name,
style: TextStyle(
color: Colors.white,
fontSize: 18.5,
),
textAlign: TextAlign.left,
),
),
),
PopupMenuButton(
icon: ImageIcon(
AssetImage("graphics/horizontal_dots.png"),
color: Colors.white,
),
itemBuilder: (_) => <PopupMenuItem<String>>[
new PopupMenuItem<String>(
child: Row(
children: <Widget>[
Icon(Icons.delete),
Text(
'Delete Album',
),
],
),
value: 'Delete',
),
],
onSelected: (value) {
deleteAlbum(albumList.elementAt(index).id, index);
}),
],
),
),
],
),
),
);
}
}
Thank you in advance.
Welcome to the flutter. Amazing platform to start you career on building cross-platform mobile applications.
My code will look a bit different to you, but trust me, this will work out for you.
Please note: You need to change some parts, like changing the image url for NetworkImage(), onTap function, Text() content etc. But not much changes in the Whole Widget code. So please look for those, and make changes accordingly. You will get there :)
GestureDetector(
onTap: () => print('Works!'), // <-- onTap change, I have used print()
child: Container(
// height of the card which contains full item
height: MediaQuery.of(context).size.height * 0.4,
width: MediaQuery.of(context).size.width * 0.28,
// this is the background image code
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
// url is my own public image url
image: NetworkImage('https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823__340.jpg')
),
borderRadius: BorderRadius.circular(12.0)
),
// this is the item which is at the bottom
child: Align(
// aligment is required for this
alignment: Alignment.bottomLeft,
// items height should be there, else it will take whole height
// of the parent container
child: Container(
padding: EdgeInsets.only(left: 10.0, right: 0.0),
height: MediaQuery.of(context).size.height * 0.1,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Text() using hard coded text right now
Text('Potraits', style: TextStyle(fontSize: 20.0, color: Colors.white, fontWeight: FontWeight.w500)),
SizedBox(height: 3.0),
Text('150 photos', style: TextStyle(fontSize: 17.0, color: Colors.white, fontWeight: FontWeight.w500))
]
)
),
// pop-up item
PopupMenuButton(
icon: Icon(Icons.more_vert, color: Colors.white),
itemBuilder: (_) => <PopupMenuItem<String>>[
new PopupMenuItem<String>(
child: Row(
children: <Widget>[
Icon(Icons.delete),
Text(
'Delete Album',
),
],
),
value: 'Delete',
),
],
onSelected: (value) {
//your function
}
)
]
)
)
)
)
)
Result
EDITS FOR WHOLE UI
So, the change required is in your buildRow Widget. You just need to give some paddings on your sides, and you are pretty much solid. Let me know
Widget buildRow(int index) {
return Padding(
padding: EdgeInsets.all(10.0),
child: AlbumTile(
index: index,
albumList: albumList,
deleteAlbum: _deleteAlbum,
)
);
}
And if you are unsatisfied with the spacings, just keep playing with the EdgeInsets painting class. I hope that helps. Please let me know. :)

flutter local notifications send ID with payload option

I have an application that stores data with sqflite. I access the records that I list with listview from the detail page with the constructor method. Short and simple codes are as follows.
notes.dart --> main page
child: ListView.builder(
itemCount: notes.length,
itemBuilder: (context, index) {
return NoteClass(
notes: notes[index],
);
},
),
note_class.dart -->
return Column(
children: <Widget>[
Dismissible(
key: UniqueKey(),
movementDuration: Duration(milliseconds: 400),
background: Container(
child: Padding(
padding: EdgeInsets.only(left: 38),
child: Align(
alignment: Alignment.centerLeft,
child: Icon(
LineIcons.trash,
color: Colors.red.shade900,
size: 27,
),
),
),
),
onDismissed: (direction) {
_deleteNote(widget.notes.noteID);
},
child: Card(
margin: EdgeInsets.only(top: 2, bottom: 2),
elevation: 2,
shape: RoundedRectangleBorder(),
child: Container(
height: 80,
child: ListTile(
onTap: (){
_detailPage(context, widget.notes);
},
contentPadding: EdgeInsets.only(left: 10, right: 5),
title: Stack(
children: <Widget>[
Container(
padding: EdgeInsets.only(top: 17),
child: Icon(Icons.note)
),
Container(
padding: EdgeInsets.only(left: 45),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Container(
padding: EdgeInsets.only(top: 0),
child: Text(
widget.notes.noteHeader,
style: TextStyle(
fontSize: 19,
color: Colors.grey[900]),
)),
Container(
padding: EdgeInsets.only(top: 0),
child: Text(
widget.notes.noteBody,
style: TextStyle(
fontSize: 17,
color: Colors.grey[900]),
),
),
],
),
],
),
),
],
),
),
),
)),
],
);
_detailPage(BuildContext context, NoteModel noteModel) {
Navigator.push(
context,
PageTransition(
type: PageTransitionType.rightToLeft,
child: NoteDetail(
content: noteModel,
)));
}
note_detail.dart
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Card(
elevation: 3,
shape: RoundedRectangleBorder(),
child: Container(
alignment: Alignment.centerLeft,
height: 50,
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.only(left: 8, top: 0),
child: SelectableText(
widget.content.noteHeader,
style: TextStyle(fontSize: 18, color: Colors.grey[800],),
),
),
),
Card(
elevation: 3,
shape: RoundedRectangleBorder(),
child: Container(
alignment: Alignment.centerLeft,
height: 50,
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.only(left: 8, top: 0),
child: SelectableText(
widget.content.noteBody,
style: TextStyle(fontSize: 18, color: Colors.grey[800],),
),
),
),],
),
On the note detail page I set notifications with flutterLocalNotificationsPlugin.schedule and I can view note details with notifications. But when I click on the notification I want to go to the detail page of the related note. I sent the ID of the record with the payload parameter.
Then, I added the onSelectNotification method in notes.dart.
Future onSelectNotification(String payload) async {
if (payload != null) {
######## what should I write here? ########
}
}
There is an ID value in payload. How can I access the note detail about ID information. Or click on the notification in which way I can go to the note detail page.
You're almost there. All you have to do is something similar to this:
class NoteDetail extends StatefulWidget {
final String payload;
NoteDetail (this.payload);
#override
State<StatefulWidget> createState() => NoteDetailState(payload);
}
class NoteDetailState extends State {
String payload;
NoteDetailState (this.payload);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar()
body:Column( your column code here))
}
// call this after something
void save() {
//dosomething
// go back to the old page
// notice the true, if all goes good with save send true otherwise false
Navigator.pop(context, true);
}
}
// use this code to go to detail
void navigateToDetail(String payload) async {
bool result = await Navigator.push(context,
MaterialPageRoute(builder: (context) => NoteDetail(payload)),
);
if (result == true) {
getData(); // refresh data from db
}
}

Updating single item on a Listview.builder widget in Flutter

so I have a list of users that is in a Listview.builder widget but my issue is that when I try to update one item on the list all the other items update as well.
I have a button that shows "Add friend" when I click on the button the message should change to "Invited", I have a string variable that holds the message so when I click on the button the string is updated from "Add friend" to "Invited", now when I click on button all the other button values change as well.
Here is my code:
class Friends extends StatefulWidget{
_FriendsState createState() => _FriendsState();
}
class _FriendsState extends State<Friends>{
List<String> nameList = [];
String btnText;
#override
Widget build(BuildContext context) {
bool showFriendList = false;
return Scaffold(
appBar: AppBar(
title: Text('Friends'),
actions: <Widget>[
IconButton(
onPressed: (){
},
icon: Icon(Icons.check, color: Colors.white,),
)
],
),
body:
Padding(
padding: EdgeInsets.all(10),
child: ListView(
children: <Widget>[
showFriendList? Column(
children: <Widget>[
Text('Find friends to add. Once they accept you can invite them to your challenge.', style: TextStyle(fontWeight: FontWeight.w500, fontSize: 16),),
SizedBox(height: 45,),
Container(
width: MediaQuery.of(context).size.width,
child: RaisedButton(
child: Text('GO AND FIND FRIENDS', style: TextStyle(fontWeight: FontWeight.w500, fontSize: 14, color: Colors.white)),
onPressed: (){
setState(() {
showFriendList != showFriendList;
});
},
color: Theme.of(context).accentColor,
shape: RoundedRectangleBorder(side: BorderSide(color: Theme.of(context).accentColor),borderRadius: BorderRadius.circular(14)),
),
)
],
): Container(
height: MediaQuery.of(context).size.height,
child:friends(context) ,
)
],
) ,
)
);
}
Widget friends(BuildContext context){
return
ListView(
children: <Widget>[
Container(
margin: EdgeInsets.all(8),
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white
),
child: TextField(
decoration:InputDecoration(
hintText: 'Enter User\'s name',
border: InputBorder.none,),
),
),
/* noRequest== true? SizedBox(height: 0,):friendRequest(context),
noRequest== true? SizedBox(height: 0,): Container(
margin: EdgeInsets.all(10),
height: 60,
child: Column(mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment:CrossAxisAlignment.start,
children: <Widget>[Text('Your friends', style: TextStyle(fontSize: 16, color: Theme.of(context).textSelectionColor,)) ],),
),*/
Container(
height: 0.5,
color: Colors.grey,
),
ListView.builder(
shrinkWrap: true,
itemCount: users.length,
itemBuilder: (BuildContext context, int index){
return
Container(
padding: EdgeInsets.only(left: 6),
height:80 ,
child:
Column(
children: <Widget>[
Row(
children: <Widget>[
users[index].profileUrl != null? CircleAvatar(child: Image.asset(users[index].profileUrl),): Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: Colors.white70,
shape: BoxShape.circle,
image: DecorationImage(
image:AssetImage('assets/plus.png') //NetworkImage(renderUrl ??'assets/img.png')
)
),
),
SizedBox(width: 30,),
Expanded(
flex: 1,
child:
Container(
child:
Row(
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 12,),
users[index].fullName != null? Text( users[index].fullName, style: TextStyle(fontSize: 18)): Text('Anjelika Thompson', style: TextStyle(fontSize: 18),),
SizedBox(height: 12,),
Row(
//crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(child: Icon(Icons.location_on),alignment: Alignment.topLeft,),
SizedBox(width: 10,),
users[index].distance_KM.toString() != null ? Text( users[index].distance_KM.toString()):Text('48.7 km')
]),
],
),
],
)
),
),
SizedBox(width: 0,),
//Icon(Icons.check,color: Colors.red,size: 40,)
FlatButton(
child: Text(btnText==null? 'ADD FRIEND': btnText, style: TextStyle(color: Color(0xff7667e5)),),
onPressed: () {
nameList.add(users[index].fullName);
setState(() {
btnText = 'INVITED';
});
},
)
],
),
Container(
height: 0.5,
color: Colors.grey,
)
],
) ,
);
}
// final item = feeds[index];
)
],
);
}
}
From my class, I have a string value called "btnText" that I use to set the new value. but at the moment once I click on one button to change from "Add friend" to "Invited" all other button Text in the listview change as well.
Please I need help figuring out what is the problem
#Chidinma, you can add a check to see if user is in your nameList,
FlatButton(
child: Text(btnText==null || !nameList.contains(users[index].fullName) ? 'ADD FRIEND': btnText, style: TextStyle(color: Color(0xff7667e5)),),
onPressed: () {
nameList.add(users[index].fullName);
setState(() {
btnText = 'INVITED';
});
................
This is just to give you an idea. A better solution would be to create a selected column in users table and save selected state as bool value. If you don't have database then i'd recommend creating indexList like nameList and save the index of invited friends and check to see if index is in the indexList like i've done with the nameList instead.
Method
inviteButtonStateFunction(index){
for (var e in invitedPeopleListIndex) {
if(e == index){
return Text("Invited");
}
}
return Text("Invite");
}
Usage
child: TextButton(
onPressed: () {
if(invitedPeopleListIndex.contains(index)){
invitedPeopleListIndex.remove(index);
}else{
invitedPeopleListIndex.add(index);
}
print(invitedPeopleListIndex);
print(invitedPeopleList);
},
child: inviteButtonStateFunction(index), // Show the text here
)

Set height of child elements equal to highest other element that are contained by Wrap Widget (Flutter)

I need to have box alignment like on image below. I use Wrap Widget to wrap my items by two elements in a row. But as i see Wrap widget don't have stretch property for the crossAxisAlignment.
I use another method to build cardItem, to simplify my code, and re-use it for my four cards.
Maybe you know some other Widgets to help to do it.
Can someone help me with it. Please see my code below:
class Transfers extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Transfers'),
),
body: Center(
child: Wrap(
spacing: 10,
runSpacing: 10,
children: <Widget>[
_buildTransferItem(
"assets/images/icon.png",
"Some Text of this box",
context,
),
_buildTransferItem(
"assets/images/icon.png",
"Text",
context,
),
_buildTransferItem(
"assets/images/icon.png",
"Some Text of this box",
context,
),
_buildTransferItem(
"assets/images/icon.png",
"Some Text of this box",
context,
),
],
),
),
);
}
Widget _buildTransferItem(
String transferIcon, String transferTitle, BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width * 0.5 - 20,
height: ,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.0),
boxShadow: [
BoxShadow(
color: Color.fromRGBO(140, 140, 140, 0.5),
blurRadius: 6.0,
)
],
),
padding: EdgeInsets.symmetric(
vertical: screenAwareSize(20.0, context),
horizontal: screenAwareSize(20.0, context),
),
child: Column(
children: <Widget>[
Image.asset(
transferIcon,
width: screenAwareSize(72.0, context),
height: screenAwareSize(39.0, context),
),
SizedBox(height: screenAwareSize(7.0, context)),
Text(
transferTitle,
style: TextStyle(
fontSize: screenAwareSize(14, context),
fontWeight: FontWeight.w300,
),
textAlign: TextAlign.center,
)
],
),
);
}
}
What you need is InstrinsicHeight widget.
Here is an example of how to solve your problem for any given number of cards in row. As you can see the _generateRows(List<String> labels, int numPerRow) function gets a collection of card labels and a number of cards in a row as input parameters and generates the layout:
List<Widget> _generateRows(List<String> labels, int numPerRow) {
Widget _buildTransferItem(String transferTitle, int numPerRow) {
return Builder(
builder: (context) {
return Container(
width: MediaQuery.of(context).size.width / numPerRow - 20,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.0),
boxShadow: [
BoxShadow(
color: Color.fromRGBO(140, 140, 140, 0.5),
blurRadius: 6.0,
)
],
),
padding: EdgeInsets.symmetric(
vertical: 20,
horizontal: 20,
),
child: Column(
children: <Widget>[
Icon(
Icons.info,
size: 48,
),
SizedBox(height: 7),
Text(
transferTitle,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w300,
),
textAlign: TextAlign.center,
)
],
),
);
},
);
}
List<Widget> result = [];
while (labels.length > 0) {
List<String> tuple = labels.take(numPerRow).toList();
for(int i = 0; i< tuple.length; i++){
if (labels.length > 0) labels.removeAt(0);
}
Widget item = IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: tuple.map((s) => _buildTransferItem(s, numPerRow)).toList(),
),
);
result.add(item);
}
return result
.expand((item) => [
item,
SizedBox(
height: 20,
),
])
.toList();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Transfers'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: _generateRows(
["Some text of this box", "Text", "Some Text of this box", "Some Rather Long Text of this box", "Cool, yeah?", "Last"],
3,
),
),
),
);
}
The IntrinsicHeight widget takes into consideration intrinsic dimensions of the child which for most container widgets like Row, etc. will be definite numbers. But it comes with performance warranty of O(N^2) in complex cases as you may read in the API docs.
Here are screenshots of cases when number of cards per row are 2 and 3. Please note that this parameter is passed just once and is not hardcoded anywhere.
If there's an odd number of items it will center last item:
The way you are applied width of Container using media Query. Same way you can apply for Height or you can write manual for example
height: 300.0,
And to match parent of Column you can write following code :
Column(
mainAxisSize: MainAxisSize.max, // match parent
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <widget>[
// your widget
]