Can someone please clarify what is the meaning and usage of "..." in Flutter?
I wanted to learn about "triple dots" used in Flutter syntax. After some reading I found out that the word I was looking for was "spreading".
Widget _build() {
List<Widget> children = [
Text("first child"),
Text("second child"),
Text("third child"),
];
return Column(
children: <Widget>[
...children,
Text("fourth child"),
],
);
}
If I didn't have the ... right before the children, it will give an error The element type 'List<Widget>' can't be assigned to the list type 'Widget'.
I just thought that someone should post a question about it. What is "..." in flutter syntax? What does it mean?
Dart 2.3 introduced the spread operator (...) and the null-aware spread operator (...?), which provide a concise way to insert multiple elements into a collection.
For example, you can use the spread operator (...) to insert all the elements of a list into another list:
var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
If the expression to the right of the spread operator might be null, you can avoid exceptions by using a null-aware spread operator (...?):
var list;
var list2 = [0, ...?list];
assert(list2.length == 1);
For more details and examples of using the spread operator, see the spread operator proposal.
I used to have this problem. I solved this problem by adding .toList(); to the List Widget.
Widget _build() {
List<Widget> children = [
Text("first child"),
Text("second child"),
Text("third child"),
].toList();
return Column(
children: <Widget>[
...children,
Text("fourth child"),
],
);
}
Hope it helps
spread operator (...) is used to provide a way to assign values to Collections, more commonly it found inside the column to render its child.
List<String> values = ['one', 'two', 'three'];
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
...values.map((value) {
return Text(value);
}),
],
),
),
);
Output:
Related
The inner map function is causing the error in the title and I don't know how I can fix this. I want to make a calculation in the inner map function before returning the Widget.
var rowOnee = Column(children: [
...stampRows.map((i) => Row(
children: [
...[0,1,2,3,4].map((i) => {
return Text("hi");
})
],
))
]);
This is not the correct way to write an anonymous function in dart:
(i) => {
return Text("hi");
}
You can either do:
(i) {
return Text("hi");
}
or
(i) => Text("hi"),
Note that the anonymous function has either => for single expression anonymous functions or {} for multiline anonymous functions, but not both.
When you have both, the {} is interpreted instead as a set literal.
That said, you really should use collection-for instead of combining ... and .map. I suggest rewriting your code as the following:
var rowOnee = Column(children: [
for (var i in stampRows)
Row(children: [
for (var i in [0, 1, 2, 3, 4]) Text("hi")
]),
]);
There are a few ways to fix it. One way is to remove the arrow:
var rowOnee = Column(children: [
...stampRows.map((i) => Row(
children: [
...[0,1,2,3,4].map((i) {
return Text("hi");
})
],
))
]);
Or you could remove the curly brackets and return statement:
var rowOnee = Column(children: [
...stampRows.map((i) => Row(
children: [
...[0,1,2,3,4].map((i) => Text("hi"))
],
))
]);
I'm new to Flutter and haven't found much success in my brief online search for an answer to this, which is the reason for this post.
Here's the code in question:
// `myList` can potentially be null.
children: widget.myList?.map((item) {
return Text("Hi.");
}).toList(),
I'm trying to loop over a List<String>? of errors in my stateful widget, inside of the children: property of a Column.
Dart is telling me that I cannot map over a List<String>?, and suggests that I use myList?.map instead.
However, when I do that, the issue now becomes that children: expects a List<Widget> and can therefore not accept a List<Widget>? ...
I seem to be stuck in circuitous errors, but somehow I feel the solution is simple. I'm still learning about null-safety.
So tl;dr:
How do I reconcile between a potentially null list of widgets, and a property that expects a list of widgets that isn't null?
Solution
children: myList?.map((e) => Text(e)).toList() ?? [],
If your List is List<Widget>?, you can add simply a null check like so:
children: _widgets?.map((item) => item).toList() ?? [Text('List was null')],
If your List is List<Widget?>? you can change it to:
children: _widgets?.map((item) => item ?? Text('widget was null')).toList() ?? [Text('List was null')],
If you want to map a List<String?> inside a Column
Column(
children: _strings.map((e) => Text(e ?? 'String was null')).toList(),
)
OR
Column(
children: _strings.map((e) => e == null ? Text('was null') : Text(e)).toList(),
)
If your List is List<String>?
Column(
children: _strings?.map((e) =>Text(e)).toList() ?? [Text('The list was null')],
)
it feels like I am doing something out of the ordinary!
I have 2 sub collections (subColl1 and subColl2) within 1 Collection in firebase firestore.
I get access to them with CollectionGroup
children: [
FutureBuilder<List<dynamic>>(
//<QuerySnapshot>(
future: Future.wait([
FirebaseFirestore.instance.collectionGroup('subColl1').get(),
FirebaseFirestore.instance.collectionGroup('subColl2').get(),
]),
Now I want to display both collections into a GridView.count() here:
return GridView.count(
restorationId: 'dashboardGridView',
crossAxisCount: 2,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
padding: const EdgeInsets.all(8),
childAspectRatio: 1,
children: <Widget>[
snapshot.data[0].docs.map<Widget>((document) {
return _DashboardGridViewItem(
document: document,
);
}).toList(),
snapshot.data[1].docs.map<Widget>((document) {
return _DashboardGridViewItem(
document: document,
);
}).toList(),
],
);
I tried individually snapshot.data[0].... and snapshot.data[1].... and they worked. But doing it like the above (which is both at the same time) throws an error type 'List<Widget>' is not a subtype of type 'Widget'
I understand the error but there must be a way to display both collections in the same gridview...
you will notice that I pass a document to a private method _DashboardGridViewItem(document: document), which is used to display information from the document. The other way I was thinking is to use a for loop surrounding the gridview and use the index i inside the snapshot.data[i]..... but then am I not returning 2 Gridviews???
need direction..
It is expecting a [Widget, Widget, Widget ..], you are instead giving [[Widgets], [Widgets]]
Simplest way to solve is to use the spread operator '...' as in below:
children: <Widget>[
...snapshot.data[0].docs.map<Widget>((document) {
return _DashboardGridViewItem(
document: document,
);
}).toList(),
...snapshot.data[1].docs.map<Widget>((document) {
return _DashboardGridViewItem(
document: document,
);
}).toList(),
],
Column(
children: <Widget>[
...myObject
.map((data) => Text("Text 1"), Text("Text 2")),
]
);
This block of code will fail because I'm returning 2 widgets instead of one. How could I fix it and return as many widget as I want without creating another column inside the map?
First you cant use an arrow function to return multiple values, you need to change it to a normal function that returns a list of widgets. Second, you need to use the .toList() method since .map is lazy and you need to iterate in order to map execute.
With this 2 steps you are going to end with a List<List<Widget>> and you should flat it before return it to a column that needs a List<Widget>. This can be achieved with the Iterable.expand() with an identity function.
You can try something like this:
Column(
children: <Widget>[
..._generateChildrens(myObjects),
],
),
And the actual implementation to obtain the widgets is:
List<Widget> _generateChildrens(List myObjects) {
var list = myObjects.map<List<Widget>>(
(data) {
var widgetList = <Widget>[];
widgetList.add(Text("Text 1"));
widgetList.add(Text("Text 2"));
return widgetList;
},
).toList();
var flat = list.expand((i) => i).toList();
return flat;
}
Hope it helps!
How to get value from an object in flutter? i need to display name of products in Text()
List<Object> _dataResponse = [
{"item":"chakka"},
{"item":"manga"},
{"item":"thenga"},
];
ListView(
children: _productName
.map((f) => ListTile(
leading: Icon(Icons.check_circle,color: Colors.green,),
title: **Text('$f["item"]')**,
))
.toList(),
)
For complex expressions (not just simple identifiers) you need to use ${...} instead of $...
Text('${f["item"]}')