flutter widgets inside for loop - flutter

I have the following code to create Row widgets based on a returned items from Future Builder
for (int i = 0; i < snapshot.data.length; i++) Row( ) ,
the above will create Rows based on the number of items from snapshot.data
what I'm trying to achieve is create multiple widget based on the length of items returned
for (int i = 0; i < snapshot.data.length; i++) {
// for each item create two rows for example
Row( ) ,
Row( ) ,
}
but I get the following error !
the element Type 'set<Row>' can't be assigned to the list 'Widget'

Try this one:
List.generate(snapshot.data.length, (index) => Row( ),),
or if you want to insert deferent widget at deferent index use:
List.generate(snapshot.data.length, (index) {
if(index == 0){return Row();}
else if(index == 1){return Column();}
else{return Container();}
),

Use ListView.builder defining the length to itemCount property.
For Example..
body: ListView.builder
(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext ctxt, int index) {
return Row();
}
)

You either use a listView.builder or for in. When you're building a widget you can't use curly braces

Related

Display ads in every nth index using Listview.builder

I am trying to place an advertisement after every 3rd index. I got the required output but my problem in my case is i have a two type of List,
List One has 50 datas in it.
List two has only 5 datas.
When i tried with the below code.
ListView.separated(
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.all(15),
shrinkWrap: true,
itemCount: articles.length,
separatorBuilder: (context, index) => SizedBox(
height: 15,
),
itemBuilder: (BuildContext context, int index) {
final Article article = articles[index];
final Sponsor sponsor = sponsors[index];
if(index %3 == 0 && index != 0) return SponsorCard(sponsor: sponsor, scaffoldKey: widget.scaffoldKey);
return Card4(article: article, heroTag: 'recent${article.id}', scaffoldKey: widget.scaffoldKey);
widget.scaffoldKey);
},
),
i am getting range error since sponsor list reached its last position.
error
The following RangeError was thrown building:
RangeError (index): Invalid value: Not in inclusive range 0..4: 49
What i need is that i need to make the sponsor list as loop so that if the List reached its last position it has to move again to the first position.
Can someone please help me on this.
You can create a new combined list as,
and make sure both Article & Sponsor class should be child class of ListItem.
OR
you need to wrap Article & Sponsor classes under ListItem Wrapper class
List items = []
Now use the items with ListView :
ListView.separated(
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.all(15),
shrinkWrap: true,
itemCount: items.length,
separatorBuilder: (context, index) => SizedBox(
height: 15,
),
itemBuilder: (BuildContext context, int index) {
if (item[index] is Articles){
return SponsorCard(..);
}else{
return Card4(...);
}
},
);
Added Example on Request comment:
class _ListItem {
final bool isArticleType;
final dynamic value;
_ListItem(this.isArticleType, this.value);
}
class Article {}
class Sponsor {}
List<_ListItem> createList(List<Article> articles, List<Sponsor> sponsors) {
List<_ListItem> items = [];
items.addAll(articles.map((e) => _ListItem(true, e)).toList());
var index = 0;
var sIndex = 0;
for (var i = 0; i < articles.length && sIndex < sponsors.length; i++) {
if (i != 0 && i % 3 == 0) {
items.insert(index, _ListItem(false, sponsors[sIndex]));
sIndex++;
index++;
}
index++;
}
return items;
}
Thanks for your response guys.
I could achieve by the below code.
itemBuilder: (BuildContext context, int index) {
actualIndex = actualIndex +1;
if(sponsorIndex+1 >= sponsors.length){
sponsorIndex = -1;
}
if(index == 0 ){
articleIndex = -1;
}
if ((actualIndex-tempIndex) % 3 == 0 && actualIndex != 0 && (actualIndex-prevIndex) >=3 ) {
tempIndex = tempIndex +1;
prevIndex = actualIndex;
sponsorIndex = sponsorIndex + 1;
final Sponsor sponsor = sponsors[sponsorIndex];
return SponsorCard(sponsor: sponsor, scaffoldKey: widget.scaffoldKey);
}
articleIndex = articleIndex + 1;
final Article article = articles[articleIndex];
return Card4(article: article, heroTag: 'recent${article.id}', scaffoldKey: widget.scaffoldKey);
},

Attempting to run a simple widget inside my program but receive the "body_might_complete_normally" error. How can I correct this?

// Build the whole list of todo items
Widget _buildTodoList() {
return new ListView.builder(
itemBuilder: (context, index) {
// itemBuilder will be automatically be called as many times as it takes for the
// list to fill up its available space, which is most likely more than the
// number of todo items we have. So, we need to check the index is OK.
if (index < _todoItems.length) {
return _buildTodoItem(_todoItems[index], index);
}
},
);
}
Attempting to run a simple widget inside my program but receive the
"body_might_complete_normally" error.
How can I correct this?
itemBuilder only return on (index < _todoItems.length), you need to make sure return widget on every case.
Widget _buildTodoList() {
return ListView.builder(
itemCount:_todoItems.length, // your list length
itemBuilder: (context, index) {
if (index < _todoItems.length) {
return _buildTodoItem(_todoItems[index], index);
}
return Text("default case");// if above condtions dont meet, return this
},
);
}

Iterate over a List of objects in Dart and present properties of object as a list in flutter

array arr = [MenuItem1, MenuItem2, MenuItem3]
class MenuItem{
String desc;
String id;
}
For the above class and array, how would I present them as a dynamic list flutter?
Rows of Row(chidren[Text((desc),Text((id)]);
After Dart 2.3 you can use Collection For:
return Row(children:
[for (MenuItem item in arr ) Text(item.desc)]
);
Since you want to return 2 Widgets for each item in the array, you can combine this with the Spread operator:
return Row(children:
[for (MenuItem item in arr ) ...[Text(item.desc),Text(item.id)]]
);
This code will help you to update the list dynamically.
ListView.builder(
itemCount: arr.length,
itemBuilder: (_, index) {
return Row(
children: <Widget>[Text(arr[index].desc), Text(arr[index].id)],
);
},
)

Streambuilder with ListView showing same data each tile?

Trying to use StreamBuilder to build out a ListView, but it is showing one item in each row of the ListView. I am using StreamBuilder broadcast. I use add(data).
child: StreamBuilder<GoogleAddress>(
stream: pickupStreamController.stream,
builder: (context, snapshot) => ListView.builder(
itemCount: 8,
itemBuilder: (context, index) {
print('Render $index');
if (snapshot.data != null) {
print("${snapshot.data.address}");
return _createListItem(
icon: Icons.location_on,
googleplace: snapshot.data,
onTap: () {
print("${snapshot.data.address}");
});
} else {}
},
),
),
Here is the StreamController code where I add to the stream. It is adding different GoogleAddress data on each iteration.
GoogleAddress addy = GoogleAddress.fromJsonMap(map);
if (sc != null) {
sc.add(addy);
}
StreamBuilder will use the latest value from the stream. To pass a list to StreamBuilder you would need to pass a list to add.
Which means to grow a list over time, you have to keep a regular list and pass it to add after modifying it.
final addresses = [];
GoogleAddress addy = GoogleAddress.fromJsonMap(map);
addresses.add(addy);
controller.add(addresses);

How can I implement number of textfields in vertical fashion

Example: https://i.stack.imgur.com/svQfv.jpg
And also the number of text fields are not fixed.
Any help will be appreciated !!
Edit:
I declared an array of controllers and an array for storing the textfield values.
List<StringBuffer> _gpas;
List<TextEditingController> _controllers;
And this is how I'm generating the fields
ListView.builder(
itemCount: widget.semestersDone,
itemBuilder: (BuildContext context, int index) {
return _createGPAInputField(
context,
'Semester ${index + 1}',
_controllers[index],
onChanged: _updateCGPA,
);
})
And this is how I'm trying to access their values in _updateCGPA function
void _updateCGPA(dynamic gpa) {
for (int i = 0; i < widget.semestersDone; ++i) {
_gpas[i].clear();
_gpas[i].write(_controllers[i].text);
}
...
}