Insert into generated list in Flutter - dart

At the moment I have this list
List.generate(72, (index) {
retrun Container(
child: new Text('$index'),
)
})
as the children of a GridView widget. What I however would like to do is return a different value than the $index for certain index values.
For this I have a List that looks like [{index: 2, value: test}{index: 5, value: hello}] with a lot of index/value pairs. So here is the question:
Is there a way now to display the value from the list in the GridView field if the matching index is in the list and if it is not simply return $index?
Just as an example, the field with the index 1 in the GridView should display its index, so it displays 1. The field with the index 2 however should display the matching value from the list, which is test and so on.

It looks like you should preprocess the list into a Map. If necessary, iterate the list adding each entry to a map.
Then you can:
Map m = <int, String>{
2: 'test',
5: 'hello',
};
List<Container>.generate(72, (int index) {
String s = m[index];
return Container(
child: Text(s != null ? s : '$index'),
);
});
or, more succinctly with the null aware operator
List<Container>.generate(
72,
(int index) => Container(child: Text(m[index] ?? '$index')),
);

Related

List.insert behavior in dart

In this code snippet
void main() {
List<int> myList = List.generate(2, (_) => 0, growable: true);
myList.addAll(List<int>.generate(1, (_) => 0));
myList.insert(3, 11);
print(myList);
}
I generate a list with two elements. Then I add a list with one element to it. So in total the original list should have 3 elements. So why does an insert at index 3 (fourth element) work? I expect an out of range error as is the case with myList.insert(4, 11).
Debug Code:
List<int> myList = List.generate(2, (_) => null, growable: true);
print("the list before adding temp list: ${myList}");
myList.addAll(List<int>.generate(1, (_) => null, growable: true));
print("the list after adding temp list: ${myList}");
myList.insert(3, 11);
print("the list after inserting an element at index 3 of combined list: ${myList}");
Debug Output:
the list before adding temp list: [null, null]
the list after adding temp list: [null, null, null]
the list after inserting an element at index 3 of combined list: [null, null, null, 11]
That's just how insert works.
The index you provide is not an element position, but the position of a gap between elements - or before the first element or after the last.
So, a list of length 3 has four gaps, the |s of: |1|2|3|. These have positions 0 through 3, and you can insert an element in any of them.
Move your mouse to List.generate you will see the following:
The created list is fixed-length if [growable] is set to false.
As you are passing true value in growable so It will increase the length of array if you will pass value False then the behavior will be changed
growable: true, it will not throw error untill you pass invalid index for example if you write myList.insert(5, 11); without writting myList.insert(4, 11); then myList.insert(5, 11); will throw error
List<int> myList = List.generate(2, (_) => 0, growable: true);
myList.addAll(List<int>.generate(1, (index) => 0));
myList.insert(3, 11);
print(myList);
growable: false It will throw error on both addAll and insert
List<int> myList = List.generate(2, (_) => 0, growable: false);
myList.addAll(List<int>.generate(1, (index) => 0));
myList.insert(3, 11);
print(myList);
Run the above different code you see the different behaviour.

Dart (Flutter) map<String, String>.map has no toList()

I have a a map structure and I want to make a DropdownMenuItem<String> for each entry. What I try to do is to call .map().toList() like this
var _languages = {
'en': 'English πŸ‡ΊπŸ‡Έ/πŸ‡¬πŸ‡§',
'fr': 'French πŸ‡«πŸ‡·',
'nl': 'Dutch',
'es': 'Spanish'
};
languages.map((key, value) => DropdownMenuItem(
value: key,
child: Text(v)
)).toList();
(if you are on a Windows, the US/GB is printed as text, if you are on any other platform, it will be flags). The problem now is twofold:
The return type 'DropdownMenuItem' isn't a 'MapEntry', as required by the closure's context.
The method 'toList' isn't defined for the type 'Map'.
How would I properly create a list out of a map? Is this not possible because a map is not an ordered collection?
Map<K, V>.map returns another Map, which isn't what you want.
You instead can create an Iterable from the Map first, and use Iterable.map, which returns another Iterable:
var menuItems = languages.entries
.map((mapEntry) =>
DropdownMenuItem(value: mapEntry.key, child: Text(mapEntry.value)))
.toList();
alternatively:
var menuItems = [
for (var mapEntry in languages.entries)
DropdownMenuItem(value: mapEntry.key, child: Text(mapEntry.value)),
];
The map method om Map is not the same as the map method on iterables (such as List). Instead of returning an Iterable, it returns a Map. As such, the inner method needs to return a MapEntry so the method can construct a new Map object to return. In order to convert this into a list, you need to convert the map itself into a list.
I'm assuming what you want to do is to take the entries in the map and map them to DropDownButton, where the language code is the button's value and the language text is the button's text. As such, you want to call map on _langages.entries, which gives you an Iterable of all the keys and values in the map. You can then call map on this iterable and it will do what you expect:
var _languages = {
'en': 'English πŸ‡ΊπŸ‡Έ/πŸ‡¬πŸ‡§',
'fr': 'French πŸ‡«πŸ‡·',
'nl': 'Dutch',
'es': 'Spanish'
};
languages.entries.map((entry) => DropdownMenuItem(
value: entry.key,
child: Text(entry.value),
)).toList();
You cannot call a .map directly in a scenario like yours as returned type is a Map<K, V>, means is a reply of the original but transformed (if you need to transform it). In your scenario you need another kind of map that is an Iterable<dynamic>. To have that you have to pass by .entries which gives you a Iterable<MapEntry<K, V>> and then call on that .map which gives you a Iterable<T> where the returned T can be even pizza :).
here a small piece of code that helps you understand the concept:
final Map<String, String> _languages = {
'en': 'English πŸ‡ΊπŸ‡Έ/πŸ‡¬πŸ‡§',
'fr': 'French πŸ‡«πŸ‡·',
'nl': 'Dutch',
'es': 'Spanish'
};
#override
Widget build(BuildContext context) {
return DropdownButton(
items: _languages.entries
.map((MapEntry element) => DropdownMenuItem(value: element.key, child: Text(element.value)))
.toList(),
onChanged: (value) {
/**/
},
);
}

How to render an Icon x amount of times - Flutter

I'm pretty new to dart/flutter so apologies if this is an obvious solution but I'm trying to render an Icon for a dynamic amount of times based on a models property.
I'm trying something like this:
Row(
children: <Widget>[
_starsForRatings()
],
)
List<Icon>_starsForRatings() {
List<Icon> stars = [];
for(int i = 0; i < _rating; i++){
stars.add(Icon(Icons.star));
}
return stars;
}
But I'm getting the error 'The element type List can't be assigned to the list type Widget' which makes sense, however I can't think of another way to render it.
Thanks
You're almost there.
The problem is that you are packing a List into another List.
What I mean is that _starsForRatings() is already returning the list you need. You don't need to put that List into another one before assigning it to the children property of the Row.
Try this instead:
Row(
children: _starsForRatings(),
)
List<Icon>_starsForRatings() {
List<Icon> stars = [];
for(int i = 0; i < _rating; i++){
stars.add(Icon(Icons.star));
}
return stars;
}

Return statement within a map with items: within Flutter DropdownButton, Why and How it works

I am new to Flutter and Dart. I'm following a free tutorial but I am confused how there is a return statement within map in items: in a DropdownButton. How does that work? I'm looking for clarification as to why the return statement is there and to where is it sending its value.
I have tried to lookup how a return statement is within a map but I may be mistaken on how to ask this question. The code works as given but I am not sure how it works. Is there a step by step simplified form of this code that may lead to more of an understanding. As it is now "it's over my head."
DropdownButton<String>(
items: _currencies.map(
(String dropDownStringItem) {
// interested in this return statement
return DropdownMenuItem<String>(
value: dropDownStringItem,
child: Text(dropDownStringItem),
);
}
).toList(), //convert to List
onChanged: (String newValueSelected) {
_onDropDownItemSelected(newValueSelected);
},
value: _currentItemSelected,
),
The naming might be confusing for someone new but let me explain for you a bit the code you've posted:
So the DropdownButton constructor expect a list of DropdownMenuItem as parameter, but in your case you don't have a list of DropdownMenuItem you have a list of String. What you need is a way to transform a String to a DropdownMenuItem, the easiest way would be to do a for over the strings, create a new DropdownMenuItem for each String you have, add it into a list and then send it to the DropdownButton. Something like:
List<DropdownMenuItem> newGenerated = [];
_currencies.forEach((value) {
DropdownMenuItem newItem = DropdownMenuItem<String>(
value: dropDownStringItem,
child: Text(dropDownStringItem),
);
newGenerated.add(newItem)
}
DropdownButton<String>(
items: newGenerated, //convert to List
onChanged: (String newValueSelected) {
_onDropDownItemSelected(newValueSelected);
},
value: _currentItemSelected,
),
The above code does the same thing as the code you have, but in my opinion is not that nice.
The function that you're using map is used to transform a list of objects into an Iterable of other elements applying a function on every element of the list that would be transformed.
One thing to keep in mind, map transforms into an Iterable and not a List(you can't cast Iterable to List), fortunately Iterable has another method called toList() that will transform it into a List.
Now in your case, the list that has to be transformed is _currencies, the function that is applied:
(String dropDownStringItem) {
// interested in this return statement
return DropdownMenuItem<String>(
value: dropDownStringItem,
child: Text(dropDownStringItem),
);
The dropDownStringItem will take value of each element in the _currencies.
The return DropdownMenuItem ... will return the transformed object
Hope that this helps.

Creating a list of widgets from map with keys and values

If I have say a SimpleDialog() and it accepts children[] and I want to populate it from a Map<int, String>, how would I do that? I need both the key and value to create the child widget.
const optionsMap = {
111:"First option",
222:"Second option",
}
return SimpleDialog(
title: Text('Choose one'),
children: // I don't know what to put here
// I want to have widgets based on optionsMap keys and values
)
I solved it by creating a List<Widget> beforehand above the return statement, but just for convenience (and becoming better in Dart) I'd like to know if there's a way to do it inline.
Update answer to incorporate #lrn 's comment
You can use map
const optionsMap = {
111:"First option",
222:"Second option",
}
return SimpleDialog(
title: Text('Choose one'),
children: optionsMap.entries.map((entry) {
var w = Text(entry.value);
doSomething(entry.key);
return w;
}).toList());
;

Resources