Thank you for reading this question.
I'm very new to dart/flutter and I'm trying to write some code so that I can create a list of the actDescriptions where they have more than 1 traits associated to them, showing the associated traits.
Thank you again.
const ACTION_DATA = const [
ActionOutput(
id: 'a1',
actDescription: 'Avoid caffeine 4 hours before going to bed for high quality sleep.',
traits: [
'T_CAFFEINE_INTAKE_BAND',
],
),
ActionOutput(
id: 'a2',
actDescription: 'Avoid caffeine altogether if you struggle with falling asleep.',
traits: [
'T_CAFFEINE_INTAKE_BAND',
'T_SLEEP_BAND',
],
),
ActionOutput(
id: 'a3',
actDescription: 'Use caffeine to boost exercise performance.',
traits: [
'T_CAFFEINE_INTAKE_BAND',
],
),
ActionOutput(
id: 'a4',
actDescription: 'If you have caffeine pre-workout, have it around 30-15 minutes before you train.',
traits: [
'T_CAFFEINE_INTAKE_BAND',
],
),
ActionOutput(
id: 'a5',
actDescription: 'Don\'t use coffee as a \"pick me up\" during the day.',
traits: [
'T_CAFFEINE_INTAKE_BAND',
],
),
];
You can use the ListView.builder constructor to create a scrollable list of your ActionOutput items. The constructor expects an itemBuilder, which is just callback function that is expected to create and return a new item for the desired index in your list.
In the example below we use the ListView.builder and delegate the item widget creation to the _buildActionItem method.
Widget _buildTraitItem(trait) {
// this can be any widget to display a trait
return Text(trait);
}
Widget _buildActionItem(ActionOutput action) {
// create a new action item
// this can be any widget, here we use a simple container with a single column
// and a row for the traits
// build a list of trait items
final traits = action.traits.map(_buildTraitItem).toList();
return Container(
height: 50,
child: Column(
children: [
Text(action.actDescription),
Row(
// use the list of items in this row
children: traits
)
]
)
);
}
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: ACTION_DATA.length,
itemBuilder: (context, index) {
// create an item for the requested index based on the item data
return _buildActionItem(ACTION_DATA[index]);
},
);
}
For more examples on how to create a list see the ListView documentation.
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 have a map like this:
static const Map<String, Map<String, String>> social = {
'personA': {
'twitch': 'https://www.twitch.tv/...',
'instagram': 'https://www.instagram.com/.../'
},
'personB': {
'twitch': 'https://www.twitch.tv/...',
'instagram': 'https://www.instagram.com/.../'
},
'personC': {
'facebook': 'https://www.facebook.com/...',
},
};
It's possible to show iconButton, with the font_awesome icon, for each
social related to each person, and on click redirect to the link?, how ?
i tried like this:
Row(
children: <Widget>[
ListView.builder(
itemBuilder: (_) {
return Constants.social[person].keys.map((e) =>
IconButton(icon: FaIcon(FontAwesomeIcons.e), onPressed: {
print("example");
});
);
}
)
],
),
but i receive the error:
The argument type 'Widget Function(BuildContext)' can't be assigned to the parameter type 'Widget Function(BuildContext, int)'
the variable person can contain personA, personB or personC.
For example for personA i want to to show 2 iconButton one for twitch and one for instagram but for personC i want to show only facebook icon.
ListView is a widget that represents a list of widgets arranged linearly.
You have multiple constructors for this widget. The one you used, ListView.builder() is the one suggested when there is a large number of children to be displayed. (In your example, if the Map contains many players.)
The default constructor only requires a List<Widget> and is considerably more simple. If you don't have a large map, I strongly suggest you to use this one instead. But since you tried using the builder one, you should do as follow:
First, have your data arranged in a List. This way you can access the elements through an integer index easily: List[0]. Ideally you should have the data already in a list form, but if you need you can convert it like this:
static const Map<String, Map<String, String>> social = {
'personA': {
'twitch': 'https://www.twitch.tv/...',
'instagram': 'https://www.instagram.com/.../'
},
'personB': {
'twitch': 'https://www.twitch.tv/...',
'instagram': 'https://www.instagram.com/.../'
},
'personC': {
'facebook': 'https://www.facebook.com/...',
},
};
List<Map<String,String>> listUsers = List().from(social.values);
For more information on these methods, check this and this.
Supply the number of itens your listview will have through the itemCount parameter:
[...]
ListView.builder(
itemCount: listUsers.length,
itemBuilder: (context, index) {
[...]
Your error says the builder function needs to receive another integer parameter:
'Widget Function(BuildContext)' can't be assigned to the parameter type
'Widget Function(BuildContext, int)```.
This integer parameter represents what widget in the list it will be. Your builder function needs to return only one widget, and it receives the index parameter so you can know which one it is:
Row(
children: <Widget>[
ListView.builder(
itemCount: listUsers.length,
itemBuilder: (context, index) {
return Column(children:[
if (listUsers[index].containsKey('twitch'))
IconButton(icon: FaIcon(FontAwesomeIcons.twitch), onPressed: (){//Access listUsers[index]['twitch'] here
}),
if (listUsers[index].containsKey('instagram'))
IconButton(icon: FaIcon(FontAwesomeIcons.instagram), onPressed: (){//Access listUsers[index]['instagram'] here
})
])
}
)
],
),
This should be enough to have your desired result. As a suggestion, you can read the official documentation which has many good examples and explanations. The Dart Language tour is also a great place for examples about the language. They are both well written and in this case would get you in the right track.
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!
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: