Single card is not single - flutter

I'm trying to make posts like on Twitter, where every post is a single separated item, but they all go like big single card, without separating. I'm kinda new with Flutter and bad at explanations, but I hope u got it.
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: _writePost,
tooltip: 'Increment',
child: Icon(Icons.create, color: Colors.grey[300]),
),
body: SizedBox(
height: 500,
child:
StreamBuilder<List<Post>>(
initialData: const [],
stream: _socketStream.stream,
builder: (context, snapshot) {
if (_isLoading) {
return const Center(
child: CircularProgressIndicator(),
);
}
return Card(child: ListView(
scrollDirection: Axis.vertical,
shrinkWrap: true,
children: [
...snapshot.data!.map<Widget>(
(post) => Padding(
key: ValueKey(post.id),
padding: const EdgeInsets.symmetric(vertical: 10),
child: ListTile(
title: Text(
post.content,
style: const TextStyle(fontSize: 20),
),
trailing: MaterialButton(
onPressed: () {
_deletePost(post.id);
},
child: const Icon(
Icons.delete,
size: 30,
),
),
),
),
)
],
) );
},
),
));
}
Example of how it looks:
I'm tried to find error with documentation, but...
Write if u need some more code or explanations.
Please help me if you can <3

You need to add each of the mapped item of your data with Card instead of your parent ListView. Something like this:
return ListView(
scrollDirection: Axis.vertical,
shrinkWrap: true,
children: [
...snapshot.data!.map<Widget>(
(post) => Padding(
key: ValueKey(post.id),
padding: const EdgeInsets.symmetric(vertical: 10),
child:
// Use card here.
Card(child: ListTile(
title: Text(
post.content,
style: const TextStyle(fontSize: 20),
),
trailing: MaterialButton(
onPressed: () {
_deletePost(post.id);
},
child: const Icon(
Icons.delete,
size: 30,
),
),
),
),
),
)
],
);

You can try ListView.separated

Try:
List.generate(lentgh, (index) {
return Text("$index"); // custom widget
}),

Related

how to scroll the screen Listview builder inside column

Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 1,
backgroundColor: appBarColor,
centerTitle: true,
title: const Text('News'),
),
body: Column(
children: [
news.length < 2
? ImageSlideshow(
children: [NewsSlideWidget0(news: news)],
)
: ImageSlideshow(
children: [
NewsSlideWidget0(news: news),
NewsSlideWidget1(news: news)
],
),
Container(
color: Colors.white,
child: ListTile(
// selectedTileColor: Colors.white,
title: Text(news_screen_title, style: news_screen_title_tstyle),
subtitle: Text(news_screen_subtitle),
),
),
news.isEmpty
? const CircularProgressIndicator()
: Expanded(
child: LazyLoadScrollView(
onEndOfPage: () => loadNextPage(),
scrollOffset: 10,
child: ListView.builder(
itemCount: news.length,
itemBuilder: (BuildContext context, int i) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NewsInnerScreen(
title: news[i].title,
date: news[i].date,
image: news[i].images[0],
content: parse(news[i].content).body!.text,
),
),
);
},
child: Container(
child: ListTile(
contentPadding: EdgeInsets.all(15),
title: Text(
news[i].title,
),
subtitle: Column(
children: [
Text(
parse(news[i].content).body!.text,
style:
),
Text(
news[i].date,
),
],
),
trailing: ConstrainedBox(
constraints: const BoxConstraints(
minWidth: 100,
minHeight: 300,
maxWidth: 104,
maxHeight: 300,
),
child: ClipRRect(
child: Image(
image: NetworkImage(
news[i].images[0],
),
),
),
),
),
),
),
);
},
),
),
),
],
),
);
}
my screen is like this I want this column to scrollable I tried singlechildscrollview and listview those did not work for me and I use a plugin for pagination and I use more widgets also and I extracted that and u I use image slide show packages for carousel so how can I do that I am new to flutter please let me know
All list builder in Flutter have property called "shrinkWrap"
Just turn it to "true"

How to sort functionality & filter data got from restapi

starting my carrer in flutter development for 2 months
while doing this project based in flutter,i get data from rest api with bloc state management & listed it with listvieww builder, but want add sort & filter functionality to it,, can you please explain how to do with an example, excepting valuable suggestions from you guys
search and filter functionilty
class Upcoming extends StatefulWidget {
Upcoming({Key? key}) : super(key: key);
#override
State<Upcoming> createState() => _UpcomingState();
}
class _UpcomingState extends State<Upcoming> {
#override
Widget build(BuildContext context) {
return BlocBuilder<MOdelBloc, MOdelState>(
builder: (context, state) {
if (state is MOdelInitial) {
context.read<MOdelBloc>().add(LoadEVENT());
return const Center(
child: CircularProgressIndicator(),
);
} else if (state is ModelLoading) {
return const Center(
child: CircularProgressIndicator(),
);
} else if (state is ModelLoadedstate) {
return buildupcoming(state.fakestore);
} else if (state is ErrorSatte) {
return const Center(
child: Text('errorstate'),
);
}
return const Center(child: Text('error'));
},
);
}
}
Widget buildupcoming(List<CryptoCurrency> currency) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.yellow.shade400,
leading: const Icon(
Icons.portrait_rounded,
),
title: const Center(
child: Text(
'Upcoming Matches',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
actions: const [
Icon(
Icons.headset,
),
SizedBox(
width: 5,
),
Icon(Icons.message)
],
),
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Container(
height: double.maxFinite,
margin: const EdgeInsets.all(10),
child:
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {}, child: const Text('CRICKET')),
const SizedBox(
width: 15,
),
ElevatedButton(
onPressed: () {},
child: const Icon(Icons.sports_football))
],
),
const SizedBox(
height: 10,
),
Row(
children: const [
TextWidget(text: 'My Rooms', size: 20),
Spacer(),
Text(
'View all',
style: TextStyle(color: Colors.black45),
)
],
),
const SizedBox(
height: 5,
),
Container(
height: 170,
child: PageView.builder(
scrollDirection: Axis.horizontal,
itemCount: 3,
itemBuilder: (context, index) {
return Container(
margin: const EdgeInsets.only(left: 5),
child: Column(children: [
SliderCARD(
text1: currency[2].fullname.toString(),
text2: currency[3].fullname,
minitext1: currency[2].price.toString(),
minitext2: currency[4].price.toString(),
color: Colors.indigo,
height: 100,
),
Row(children: [IconButton(onPressed: ( ){},
icon: Icon(Icons.arrow_back)),IconButton(onPressed: (){}, icon: Icon(Icons.arrow_back_outlined))],)]));
})),
ListView.builder(
physics:const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: currency.length,
itemBuilder: (context, index) {
final CryptoCurrency cryptoCurrency = currency[index];
return Container(
margin: const EdgeInsets.only(bottom: 10),
height: 100,
child: SliderCARD(
text1: cryptoCurrency.fullname,
text2: currency[3].fullname,
minitext1: cryptoCurrency.price.toString(),
minitext2: currency[4].price.toString(),
color: Colors.white,
height: 100,
));
})
])),
));
}

ListView doesn't separate objects from doc

I'm trying to create scrollable list of posts, but instead i got static non-scrollable bloc of strings, which is overflowing.
Example:
Oveflowing:
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: _writePost,
tooltip: 'Increment',
child: Icon(Icons.create, color: Colors.grey[300]),
),
body: SizedBox(
child: Container(
child: Column(children: [
StreamBuilder<List<Post>>(
initialData: const [],
stream: _socketStream.stream,
builder: (context, snapshot) {
if (_isLoading) {
return const Center(
child: CircularProgressIndicator(),
);
}
ListView(
scrollDirection: Axis.vertical,
shrinkWrap: true,
children: [
...snapshot.data!.map<Widget>(
(post) => Padding(
key: ValueKey(post.id),
padding: const EdgeInsets.symmetric(vertical: 10),
child: ListTile(
title: Text(
post.content,
style: const TextStyle(fontSize: 20),
),
trailing: MaterialButton(
onPressed: () {
_deletePost(post.id);
},
child: const Icon(
Icons.delete,
size: 30,
),
),
),
),
)
],
);
},
),
]))));
}
Moreover, they all go like a single card, without separating.
Edited code, which is scrolling but doesn't separate posts
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: _writePost,
tooltip: 'Increment',
child: Icon(Icons.create, color: Colors.grey[300]),
),
body: SizedBox(
height: 500,
child:
StreamBuilder<List<Post>>(
initialData: const [],
stream: _socketStream.stream,
builder: (context, snapshot) {
if (_isLoading) {
return const Center(
child: CircularProgressIndicator(),
);
}
return Card(child: ListView(
scrollDirection: Axis.vertical,
shrinkWrap: true,
children: [
...snapshot.data!.map<Widget>(
(post) => Padding(
key: ValueKey(post.id),
padding: const EdgeInsets.symmetric(vertical: 10),
child: ListTile(
title: Text(
post.content,
style: const TextStyle(fontSize: 20),
),
trailing: MaterialButton(
onPressed: () {
_deletePost(post.id);
},
child: const Icon(
Icons.delete,
size: 30,
),
),
),
),
)
],
) );
},
),
));
}
I'm tried to find error with documentation, but...
Column and Listview take the maximum available height. therefore, the height of Listview which here is a child of Column should be constrained. You can do so by wrapping your ListView inside Expanded:
child: Column(
children: [
Expanded(
child: ListView(
Also, if your list is long, it is not recommended to set shrinkwrap to true. Because it makes the ListView to load all its items when the layout gets built. So it can slow down performance.
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: _writePost,
tooltip: 'Increment',
child: Icon(Icons.create, color: Colors.grey[300]),
),
body: SizedBox(
height: MediaQuery.of(context).height*0.8, // add this line
child:
// Container( // do not need this
// child: // and this do not need
// Column(children: [ // and this do not need
StreamBuilder<List<Post>>(
initialData: const [],
stream: _socketStream.stream,
builder: (context, snapshot) {
if (_isLoading) {
return const Center(
child: CircularProgressIndicator(),
);
}
ListView( // change this to ListView.builder for more performance
scrollDirection: Axis.vertical,
shrinkWrap: true,
children: [
...snapshot.data!.map<Widget>(
(post) => Padding(
key: ValueKey(post.id),
padding: const EdgeInsets.symmetric(vertical: 10),
child: ListTile(
title: Text(
post.content,
style: const TextStyle(fontSize: 20),
),
trailing: MaterialButton(
onPressed: () {
_deletePost(post.id);
},
child: const Icon(
Icons.delete,
size: 30,
),
),
),
),
)
],
);## Heading ##
},
),
// ]) // comment this
// ). // and comment this
)
);
}

Loop Cards Flutter

I have been researching Flutter and a question arose --
I have an array with some information, and I need to add cards based on this array.
Currently, I create a loop and add the cards which follow the structure of my array and my program listed below. Note that when I call statement passing the parameters, the code runs without any problem, but the following code does not work for me:
import "package:acessorias/pages/global.variables.dart";
import "package:flutter/material.dart";
class Comunicados extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
title: Center(
child: SizedBox(
width: 150,
child: Image.asset("assets/image/logo.png"),
),
),
actions: <Widget>[
Container(
width: 60,
child: FlatButton(
child: Icon(
Icons.search,
color: Color(0xFFBABABA),
),
onPressed: () => {},
),
),
],
),
body: Container(
color: Color(0xFFF2F3F6),
child: ListView(
children: <Widget>[
comunicado(comunicados[0]["LogNome"], comunicados[0]["EmComDTH"],
comunicados[0]["EmComDesc"]),
comunicado(comunicados[1]["LogNome"], comunicados[1]["EmComDTH"],
comunicados[1]["EmComDesc"]),
comunicado(comunicados[2]["LogNome"], comunicados[2]["EmComDTH"],
comunicados[2]["EmComDesc"]),
comunicado(comunicados[3]["LogNome"], comunicados[3]["EmComDTH"],
comunicados[3]["EmComDesc"]),
comunicado(comunicados[4]["LogNome"], comunicados[4]["EmComDTH"],
comunicados[4]["EmComDesc"]),
comunicado(comunicados[5]["LogNome"], comunicados[5]["EmComDTH"],
comunicados[5]["EmComDesc"])
],
),
),
);
}
}
Widget comunicado(user, data, msg) {
return Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage("assets/image/foto.png"),
),
title: new Text(user),
subtitle: Text(data),
trailing: Icon(Icons.more_vert),
),
/*Container(
child: Image.asset("assets/image/post.png"),
),*/
Container(
padding: EdgeInsets.all(10),
child: Text(msg),
),
ButtonTheme.bar(
child: ButtonBar(
children: <Widget>[
FlatButton(
child: Icon(Icons.favorite),
onPressed: () {},
),
FlatButton(
child: Icon(Icons.share),
onPressed: () {},
),
],
),
),
],
),
);
}
Solution
body: ListView.builder(
itemCount: comunicados.length,
itemBuilder: (context, index) {
/*return ListTile(
title: Text('${comunicados[index]}'),
);*/
return comunicado(comunicados[index]['LogNome'],
comunicados[index]["EmComDTH"], comunicados[index]["EmComDesc"]);
},
),
You can use data model in another dart file like Comunicado.dart
class Comunicado{
String user;
String data;
String msg;
Comunicado(
{this.user, this.data, this.msg});
}
after that you can make list of data model with the static data or etc like
List getComunicado(){
return[
Comunicado(
user: comunicados[0]["LogNome"],
data: comunicados[0]["EmComDTH"],
msg: comunicados[0]["EmComDesc"],
),
Comunicado(
user: comunicados[1]["LogNome"],
data: comunicados[1]["EmComDTH"],
msg: comunicados[1]["EmComDesc"],
),
]
}
in my case, i put it into initial state and don't forget to declare comm
#override
void initState() {
super.initState();
comm= getComunicado();
}
for custom card
Card makeCard(Comunicado newComm) => Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage("assets/image/foto.png"),
),
title: new Text("${newComm.user}"),
subtitle: Text("${newComm.data}"),
trailing: Icon(Icons.more_vert),
),
/*Container(
child: Image.asset("assets/image/post.png"),
),*/
Container(
padding: EdgeInsets.all(10),
child: Text("${newComm.msg}"),
),
ButtonTheme.bar(
child: ButtonBar(
children: <Widget>[
FlatButton(
child: Icon(Icons.favorite),
onPressed: () {},
),
FlatButton(
child: Icon(Icons.share),
onPressed: () {},
),
],
),
),
],
),
);
and for last you can call make card on listview
ListView.builder(
scrollDirection: Axis.vertical,
itemCount: comm.length,
itemBuilder: (BuildContext context, int index) {
return makeCard(comm[index]);
},
),

Flutter dynamic height of ListView

I am developing a Flutter application and I want to dynamically adjust the height of the ListView.
I want the list to have a maximum height of 200. If the height is more than that, user will have to scroll to reach the bottom. If height is below 200, it will take only as much space as needed.
Preview of application: Screenshot. As you can see Restaurants nearby is pushed to the very bottom of the page. I want the ListView to only take height of 200 or less so that the content below isn't pushed to the bottom.
Here is my current code:
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Restaurants nearby',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('Enter restaurant manually'),
onPressed: () {
print('Button pressed');
},
),
],
),
Flexible(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: Colors.cyan,
),
title: Text('Test restaurant'),
subtitle: Text('80m'),
);
},
itemCount: 15,
),
),
Text(
'Restaurants nearby',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
],
),
);
}
You are using Flexible widget, that's why your ListView expands. You have to change Flexible to ConstrainedBox and add shrinkWrap: true to your ListView.
ConstrainedBox(
constraints: BoxConstraints(maxHeight: 200, minHeight: 56.0),
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: Colors.cyan,
),
title: Text('Test restaurant'),
subtitle: Text('80m'),
);
},
itemCount: 15,
),
),
More info here: https://api.flutter.dev/flutter/widgets/ConstrainedBox-class.html
You can use LimitedBox
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(...),
Divider(),
Row(...),
LimitedBox(
maxHeight: 200.0,
child: ListView.builder(...),
),
Text(...),
],
),
Recommended solution in case when the incoming constraints are unbounded
Consider wrapping the ListView into this
LimitedBox(
maxHeight: 200,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: Colors.cyan,
),
title: Text('Test restaurant'),
subtitle: Text('80m'),
);
},
itemCount: _itemsCount,
),
),
]
)
),
Note that:
shrinkWrap of ListView is set to true
mainAxisSize of Column is set to MainAxisSize.min
maxHeight of LimitedBox is set to 200
A complete snippet:
import 'package:flutter/material.dart';
class DebugWidget extends StatefulWidget {
#override
_DebugWidgetState createState() => _DebugWidgetState();
}
class _DebugWidgetState extends State<DebugWidget> {
int _itemsCount = 1;
#override
Widget build(BuildContext context) {
Widget child = Container(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Restaurants nearby',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('Enter restaurant manually'),
onPressed: () {
print('Button pressed');
},
),
RaisedButton(
child: Text('+1'),
onPressed: () {
setState(() {
_itemsCount += 1;
});
},
),
RaisedButton(
child: Text('-1'),
onPressed: () {
setState(() {
_itemsCount -= 1;
});
},
),
],
),
LimitedBox(
maxHeight: 200,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: Colors.cyan,
),
title: Text('Test restaurant'),
subtitle: Text('80m'),
);
},
itemCount: _itemsCount,
),
),
]
)
),
Text(
'Restaurants nearby',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
],
),
);
return Scaffold(
body: child,
);
}
}
I found a solution to this problem. you should wrap your ListView with LimittedBox or ConstraintBox and give them maxHeight and set shrinkWrap property of ListView to true. the solution would be something like this.
LimitedBox(
maxHeight: 200,
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: Colors.cyan,
),
title: Text('Test restaurant'),
subtitle: Text('80m'),
);
},
itemCount: 15,
),
),
I see that this question has never been answered only with giving a fixed height, so here is what works for me.
For some reason if you set the shrinkwrap to true it doesn't look like it is working but it does, the problem is in the padding settings of the ListView, set the padding to edgeinstets.zero. That fixes it for me.
Wrap inside a Flexible
ShrinkWrap true
Padding, zero
and if needed the column to MainAxisSize.min.
Hope it helps some people.
Example of my code:
Flexible(
child: Container(
decoration: BStyles.cardDecoration1,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text(
'PRODUCTION TASKS',
),
const SizedBox(
height: textVerticalSpacing,
),
Flexible(
child: ListView.builder(
itemCount: recentTasks.length,
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return TaskCard(
task: recentTasks[index],
widthInfo: MediaQuery.of(context).size.width * 0.6,
);
},
),
),
const SizedBox(
height: itemSpacing,
),
Align(
alignment: Alignment.centerRight,
child: InkWell(
onTap: () { },
child: const Text(
'View more',
),
),
),
const SizedBox(
height: textVerticalSpacing,
),
],
),
),
),
),
ConstrainedBox(
constraints: BoxConstraints(maxHeight: 200.0),
child: [your child here],
)
This make your child's height not bigger than 200.0
You can always size the ListView container as % of the viewport (assuming of course that the other widgets also are sized in the same manner):
return Container(
height: MediaQuery.of(context).size.height * 0.75,
child: ListView.builder(
itemBuilder: (ctx, index) {
return Card(...