I entered the data from json, everything works fine, but now only the first element is displayed. How can I write here like foreach so that all elements with a loop are displayed.
You can see the code here
You should wrap the data with listview builder.
Try code something like this:
...
else if(snapshot.hasData ){
return ListView.builder (
itemCount: snapshot.data.length, \\length of snapshot data
itemBuilder: (BuildContext ctxt, int index) {
return Container(
child:Column(
children: <Widget>[
new Padding(padding: const EdgeInsets.all(5.0)),
new Container(
child: new Text(
'Тип штрафа: ${data[index]['VDescription']}'
),
),
new Container(
child: new Text(
'Адрес: ${data[index]['VLocation']}'
),
),
new Container(
child: new Text(
'Дата: ${data[index]['VTime']}'
),
),
],
),
);
}
);
I hope this will work. :)
Related
I am building a listview from a Firestore Database. I originally wanted to separate my items by ListTiles since I know they can do separators, but I was not getting the height that I wanted out of the tiles, so I moved to transparent Cards.
Problem is I cannot figure out how to add a separator or divider after each card.
Here is my code so far
Widget build(BuildContext context) {
if (snapshot == null) return CircularProgressIndicator();
return Scaffold(
body: ListView.builder(
itemCount: snapshot.length,
itemBuilder: (context, index){
return Card(
elevation: 0,
color: Colors.transparent,
child: Row(
children: <Widget>[
Padding(padding: EdgeInsets.all(10.0),),
Column(
children: <Widget>[
Padding(padding: EdgeInsets.all(10.0),),
Text(snapshot[index].data["month"], style:
TextStyle(fontSize: 30, fontWeight:
FontWeight.w300),),
Text(snapshot[index].data["day"], style:
TextStyle(fontSize: 20),),
],
)
],
),
);
}
),
);
}
}
Desired
Current
I would think list tiles would work better, but I tried what I knew how to do to build custom list tiles and i could not replicate the results.
Use ListView.separated
ListView.separated(
separatorBuilder: (context, index) => Divider(
color: Colors.black,
),
itemCount: 20,
itemBuilder: (context, index) => Padding(
padding: EdgeInsets.all(8.0),
child: Center(child: Text("Index $index")),
),
)
or divideTiles()
ListView(
children: ListTile.divideTiles(
context: context,
tiles: [
// your widgets here
]
).toList(),
)
When I'm, not using the ListView.builder constructor in Flutter, the individual item is shown as expected from the JSON API:
when I use ListView.builder, nothing shows up. no Error!
I also tried a listview with Texts only that doesn't seem to work either.
Here's the code:
#override
Widget build(BuildContext context) {
return Container(
child: new Scaffold(
appBar: AppBar(
title: Text("the title"),//TODO edit this
backgroundColor: Colors.blueAccent),
body:
Column(
children: <Widget>[
FutureBuilder<List<dynamic>>(
future: getPosts2(),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData
? ListViewPosts(postsFrom: snapshot.data)
: Center(child: CircularProgressIndicator());
},
),
],
),
),
);
}
}
And here is the ListViewPosts Stateless Widget:
class ListViewPosts extends
StatelessWidget {
final List<dynamic> postsFrom;
ListViewPosts({Key key,
this.postsFrom}) : super(key: key);
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
FadeInImage.assetNetwork(
placeholder: 'assets/images/placeholder.png',
image: postsFrom[1]["featured_media"] == 0
? 'assets/images/placeholder.png'
: postsFrom[1]["_embedded"]["wp:featuredmedia"]
[0]["source_url"],
),
FadeInImage.assetNetwork(
placeholder: 'assets/images/placeholder.png',
image: postsFrom[2]["featured_media"] == 0
? 'assets/images/placeholder.png'
: postsFrom[2]["_embedded"]["wp:featuredmedia"]
[0]["source_url"],
),
new Row(
children: <Widget>[
Expanded(
child: Text(
"نووسهر: " +
postsFrom[1]["_embedded"]["author"][0]
["name"],
textAlign: TextAlign.right,
),
),
Expanded(
child: Text(
dateConvertor(
postsFrom[2]["date"].toString()),
textAlign: TextAlign.left,
),
),
],
),
ListView.builder(
itemCount: postsFrom.length, //== null ? 0 : postsFrom.length,
itemBuilder: (context, int index) {
Card(
child: Column(
children: <Widget>[
Text(postsFrom.toString()),
Container(
child: hawalImage(postsFrom, index),
),
new Padding(
padding: EdgeInsets.all(5.0),
child: new ListTile(
title: new Text("whatEver"),
subtitle: new Row(
children: <Widget>[
Expanded(
child: new Text(postsFrom[index]["title"]["rendered"]),
),
Expanded(
child: hawalDate(postsFrom, index),
),
],
),
),
),
new ButtonTheme.bar(
child: hawalBtnBar(),
),
],
),
);
},
),
You have to write return Card at the beginning of the curly brackets in the builder function. Also I would be cautious with using Expanded there, it might cause some errors.
Also you put a ListView inside a Column without defining it's height, so it will take up space indefinitely. Wrap it in a widget that provides height constraints(SizedBox, Expanded, ...)
Inside the Listview.builder() you could try to add the property shrinkWrap: true.
This worked for me. I was facing a similar issue.
Use with Expanded. Hopefully, it will solve your problem.
You have to write return Card at the beginning of the curly brackets in the builder function. Also I would be cautious with using Expanded there, it might cause some errors.
I've added a list element by using the following method:
listToAddTo.add(italianFood());
However, when I try removing the same element by using the method:
listToAddTo.remove(italianFood());
it does not work.
I've tried using the removeWhere method with the parameters item == italianFood(), the retainWhere method with the item != italianFood() parameters, and the removeAt method with the listToAddTo.indexOf(italianFood()) parameters, however, none of those seem to work.
When I try printing the list, I get the following result:`
ListView(
scrollDirection: vertical,
primary: using primary controller,
scrollPhysics: AlwaysScrollableScrollPhysics,
shrinkWrap: shrink-wrapping
)
Above methods with this result also seem to have no effect.
Necessary code is as follows:
List listToAddTo = [];
ListView italianFood() {
return ListView(
shrinkWrap: true,
children: <Widget>[
listEntry(
'Fast Food Nana',
'Mon - Sun 06:00 - 04:00',
Container(
child: IconButton(
icon: Icon(
Icons.motorcycle,
size: 30.0,
),
),
),
IconButton(
icon: Icon(
Icons.navigation,
size: 30.0,
),
),
),
],
);
Container filterItem(String label, value, onChanged) {
return Container(
decoration: BoxDecoration(color: Colors.white),
child: CheckboxListTile(
value: value,
title: Text(label),
onChanged: onChanged,
),
);
bool isTrue = false;
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Container(
margin: const EdgeInsets.only(top: 45.0),
child: ListView.builder(
itemCount: listToAddTo.length,
itemBuilder: (BuildContext context, int Index) {
return (listToAddTo[Index]);
},
),
),
ExpansionTile(
title: Text('Filters'),
children: <Widget>[
filterItem(
'Italian',
isTrue,
(bool value) {
setState(() {
if (isTrue == false) {
listToAddTo.add(italianFood());
isTrue = !isTrue;
} else {
listToAddTo.removeAt(listToAddTo.indexOf(italianFood()));
isTrue = !isTrue;
}
});
print(listToAddTo);
print(italianFood());
},
),
],
),
],
);
You can't remove it because are different objects.
Every time you use italianFood() you create a new instance of the class.
Create a gloval variable :
ListView _myItalianFood;
Instantiate:
in your add method:
_myItalianFood = italianFood();
listToAddTo.add(_myItalianFood);
Remove:
listToAddTo.remove(_myItalianFood);
The problem is that italianFood() returns a new ListView instance on each call. So when you call listToAddTo.add(italianFood()) you are creating a new ListView instance (let's call it LV1) and you end up with listToAddTo being [LV1].
When you call listToAddTo.remove(italianFood()) you are creating a new ListView instance (let's call it LV2) and asking listToAddTo to remove anything that is equal to LV2, so this ends up doing nothing since LV2 is not in listToAddTo.
You could fix this by making italianFood a field.
final italianFood = ListView(shrinkWrap: true, ...);
new Expanded(
child: _searchResult.length != 0 || controller.text.isNotEmpty
? new ListView.builder(
itemCount: _searchResult.length,
itemBuilder: (context, int i) {
return new Card(
child: new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Row(children: <Widget>[
//new GestureDetector(),
new Container(
width: 45.0,
height: 45.0,
decoration: new BoxDecoration(
shape: BoxShape.circle,
image: new DecorationImage(
fit: BoxFit.fill,
image: new NetworkImage(
"https://raw.githubusercontent.com/flutter/website/master/_includes/code/layout/lakes/images/lake.jpg")))),
new Text(
" " +
userDetails[returnTicketDetails[i]
["user_id"]]["first_name"] +
" " +
(userDetails[returnTicketDetails[i]
["user_id"]]["last_name"]),
style: const TextStyle(
fontFamily: 'Poppins', fontSize: 20.0)),
]),
new Column(
children: <Widget>[
new Align(
alignment: FractionalOffset.topRight,
child: new FloatingActionButton(
onPressed: () {
groupId = returnTicketDetails[i]["id"];
print(returnTicketDetails[i]["id"]);
print(widget.id);
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new Tickets(groupId,widget.id)));
},
heroTag: null,
backgroundColor: Color(0xFF53DD6C),
child: new Icon(Icons.arrow_forward),
)),
new Padding(padding: new EdgeInsets.all(3.0)),
],
)
]));
},
)
: new ListView.builder(
itemCount: _searchResult.length,
itemBuilder: (context, int i) {
return new Card(
child: new ListTile(
//title: new Text(userDetails[returnTicketDetails[i]["user_id"]]["first_name"]),
),
margin: const EdgeInsets.all(0.0),
);
},
),
),
Hi everyone! As I am building dynamically a Card in a ListView, I was thinking rather than keep the FloatingActionButton in each of them as I already do, to implement a onTap method in each card and trigger something.
In other words, I would like to keep the card as simple as possible without many widget around.
Thank you in advance!
As Card is "a sheet of Material", you probably want to use InkWell, which includes Material highlight and splash effects, based on the closest Material ancestor.
return Card(
child: InkWell(
onTap: () {
// Function is executed on tap.
},
child: ..,
),
);
You should really be wrapping the child in InkWell instead of the Card:
return Card(
child: InkWell(onTap: () {},
child: Text("hello")));
This will make the splash animation appear correctly inside the card rather than outside of it.
Just wrap the Card with GestureDetector as below,
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return new ListView.builder(
itemBuilder: (context, i) {
new GestureDetector(
child: new Card(
....
),
onTap: onCardTapped(i),
);
},
);
}
onCardTapped(int position) {
print('Card $position tapped');
}
}
I get an error while I'm building the ListView, At first I thought the API wasn't returning anything but I printed the movies variable in flutter and it consoled log the values.
Btw I'm trying to recreate this project:
https://github.com/mlabouardy/flutter-watchnow
The error I get is:
RangeError (index): Invalid value: Valid value range is empty: 0
This is the list view builder:
class TopMoviesState extends State<TopMovies> {
List<Movie> _movies = new List();
final _apiGatewayURL = "https://gfioehu47k.execute-api.us-west-1.amazonaws.com/staging/main";
Widget _fetchMovies() {
return new ListView.builder(
padding: const EdgeInsets.all(16.0),
itemBuilder: (context, i){
return new Card(
child: new Container(
height: 250.0,
child: new Padding(
padding: new EdgeInsets.all(2.0),
child: new Row(
children: <Widget>[
new Align(
child: new Hero(
child: new Image.network("https://image.tmdb.org/t/p/w500"+this._movies[i].getPoster()),
tag: this._movies[i].getTitle()
),
alignment: Alignment.center,
),
new Expanded(
child: new Stack(
children: <Widget>[
new Align(
child: new Text(
this._movies[i].getTitle(),
style: new TextStyle(fontSize: 11.0, fontWeight: FontWeight.bold),
),
alignment: Alignment.topCenter,
),
new Align(
child: new Padding(
padding: new EdgeInsets.all(4.0),
child: new Text(
this._movies[i].getOverview(),
maxLines: 8,
overflow: TextOverflow.ellipsis,
style: new TextStyle(fontSize: 12.0, fontStyle: FontStyle.italic)
)
),
alignment: Alignment.centerRight,
),
new Align(
child: new Text(
this._movies[i].getReleaseDate(),
style: new TextStyle(fontSize: 11.0, fontWeight: FontWeight.bold),
),
alignment: Alignment.bottomRight,
),
]
)
)
]
)
)
)
);
}
);
}
This is how I'm running through each value I'm getting from the API:
void _addMovie(dynamic movie){
this._movies.add(new Movie(
title: movie["title"],
overview: movie["overview"],
poster: movie["poster_path"],
releaseDate: movie["release_date"]
));
}
#override
void initState() {
super.initState();
http.get(this._apiGatewayURL)
.then((response) => response.body)
.then(json.decode)
.then((movies) {
movies.forEach(_addMovie);
});
}
You are not specifying an itemCount to ListView. So if you ever have enough space to display more then the number of items available, you'll try to access _movies at an invalid index. Resulting in this error.
Try to add
new ListView(
...
itemCount: _movie.length
you need to add item count
new ListView(
...
itemCount: _movie.length
without it ListView.Builder not know the position of list and and we are not showing the list according to position
Try to add the index of listview.builder,
Listview.builder is used for a very long or unknown set of lists, which you are doing correct.
Just count the number of values you are getting from the API response and add the index as a parameter.
For more reference, check this URL:
https://docs.flutter.io/flutter/widgets/ListView/ListView.builder.html