I'm just getting started with Flutter.
What is the recommended way to layout a list of cards on a screen?
Some cards will have only contain a single object as a line of text, but others that contain multiple objects as lines of text should also have a header within the card.
For example, here is a mock-up that I drew that I'm trying to accomplish.
Flutter doesn't like a ListView inside a Card. It generates the following errors:
I/flutter (13243): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter (13243): The following assertion was thrown during performResize():
I/flutter (13243): Vertical viewport was given unbounded height.
I/flutter (13243): Viewports expand in the scrolling direction to fill their container.In this case, a vertical
I/flutter (13243): viewport was given an unlimited amount of vertical space in which to expand. This situation
I/flutter (13243): typically happens when a scrollable widget is nested inside another scrollable widget.
I/flutter (13243): If this widget is always nested in a scrollable widget there is no need to use a viewport because
I/flutter (13243): there will always be enough vertical space for the children. In this case, consider using a Column
I/flutter (13243): instead. Otherwise, consider using the "shrinkWrap" property (or a ShrinkWrappingViewport) to size
I/flutter (13243): the height of the viewport to the sum of the heights of its children.
With #aziza's help, I banged out the following code with provides a base layout very close to what I mocked up, but I have a couple of questions:
Is this the most efficient use of nested widgets?
Is there any way to set a global font size so that I don't have to set it on every Text widget?
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My Layout',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'App Bar Title'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List itemList = [
'Card Text 2 Line 1',
'Card Text 2 Line 2',
'Card Text 2 Line 3',
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Sub Title',
style: TextStyle(
fontSize: 25.0,
),
),
],
),
),
Row(
children: [
Expanded(
child: Card(
shape: RoundedRectangleBorder(
side: BorderSide(
width: 3.0,
),
),
margin: EdgeInsets.all(15.0),
color: Colors.grey,
elevation: 10.0,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Card 1 Text',
style: TextStyle(
fontSize: 25.0,
),
),
),
),
),
],
),
Row(
children: [
Expanded(
child: Card(
shape: RoundedRectangleBorder(
side: BorderSide(
width: 3.0,
),
),
margin: EdgeInsets.all(15.0),
color: Colors.grey,
elevation: 10.0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Card 2 Header',
style: TextStyle(
fontSize: 25.0,
),
),
],
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: List.generate(
itemList.length,
(i) => Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
itemList[i],
style: TextStyle(
fontSize: 25.0,
),
),
),
),
),
],
),
),
),
],
),
Row(
children: [
Expanded(
child: Card(
shape: RoundedRectangleBorder(
side: BorderSide(
width: 3.0,
),
),
margin: EdgeInsets.all(15.0),
color: Colors.grey,
elevation: 10.0,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Card 3 Text',
style: TextStyle(
fontSize: 25.0,
),
),
),
),
),
],
)
],
),
),
);
}
}
CardModel: Represents each list item, which contains an optional header and list of strings. Building ListView: If header field is persent it is added in a column, then the list of strings of the card are added to the above column as well. At the end these individually created cards are wrapped as a list and displayed inside the ListView.
import 'package:flutter/material.dart';
void main() => runApp(
new MaterialApp(
debugShowCheckedModeBanner: false,
home: new CardsDemo(),
),
);
class CardsDemo extends StatefulWidget {
#override
_CardsDemoState createState() => new _CardsDemoState();
}
class _CardsDemoState extends State<CardsDemo> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Cards'),
),
body: new Column(
children: <Widget>[
new Center(
child: new Padding(
padding: const EdgeInsets.all(15.0),
child: new Text(
'Sub Title',
style:
new TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold),
),
),
),
new Expanded(
child: new ListView(
children: _buildCards(),
padding: const EdgeInsets.all(8.0),
),
),
],
),
);
}
Widget _buildCard(CardModel card) {
List<Widget> columnData = <Widget>[];
if (card.isHeaderAvailable) {
columnData.add(
new Padding(
padding: const EdgeInsets.only(bottom: 8.0, left: 8.0, right: 8.0),
child: new Text(
card.headerText,
style: new TextStyle(fontSize: 24.0, fontWeight: FontWeight.w500),
),
),
);
}
for (int i = 0; i < card.allText.length; i++)
columnData.add(
new Text(card.allText[i], style: new TextStyle(fontSize: 22.0),),
);
return new Card(
child: new Padding(
padding: const EdgeInsets.symmetric(vertical: 15.0),
child: Column(children: columnData),
),
);
}
List<Widget> _buildCards() {
List<Widget> cards = [];
for (int i = 0; i < sampleCards.length; i++) {
cards.add(_buildCard(sampleCards[i]));
}
return cards;
}
}
class CardModel {
final String headerText;
final List<String> allText;
final bool isHeaderAvailable;
CardModel(
{this.headerText = "", this.allText, this.isHeaderAvailable = false});
}
List<CardModel> sampleCards = [
new CardModel(allText: ["Card 1 Text"]),
new CardModel(
isHeaderAvailable: true,
headerText: "Card 2 Header",
allText: ["Card 2 Text Line 1", "Card 2 Text Line 2"]),
new CardModel(allText: ["Card 3 Text"]),
];
Related
I am trying to create an app bar that looks like the following image when expanded
When collapsing I only need the initial column of text to be available in the app bar, so the image should fade away and the text column to animate and become the Appbar title
I have tried using SliverAppBar with a custom scroll view but the Flexible space's title is not looking good also I don't know how to make the image disappear alone and show only the text when collapsed.
As of now, this is the expanded state
And when I try to collapse it, this happens
Here's the code for the same
CustomScrollView(
slivers: [
SliverAppBar(
pinned: true,
leading: GestureDetector(
onTap: () => Get.back(),
child: const Icon(
Icons.arrow_back,
color: Colors.black,
),
),
flexibleSpace: FlexibleSpaceBar(
title: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Row(
children: [
const Expanded(
child: Text.rich(
TextSpan(
text: "Buffet Deal\n",
style:
TextStyle(color: Colors.black, fontSize: 14),
children: [
TextSpan(
text: "Flash Deal",
style: TextStyle(
color: Colors.black, fontSize: 10),
),
]),
),
),
if (_model.imgUrl != null)
CachedNetworkImage(
imageUrl: _model.imgUrl!,
),
const SizedBox(
width: 18,
)
],
),
),
),
expandedHeight: Get.height * 0.2,
backgroundColor: const Color(0xFFFFF4F4)),
SliverToBoxAdapter(
child: Container()
)
],
),
Your help is appreciated. Thanks in advance
To make the SliverAppBar's flexible space image disappear whenever the expanded space collapse just use the FlexibleSpaceBar.background property.
To solve the overlapping text just wrap the FlexibleSpaceBar around a LayoutBuilder to get if it's expanded or not and adjust the text positioning.
Check out the result below (Also, the live demo on DartPad):
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final expandedHeight = MediaQuery.of(context).size.height * 0.2;
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
pinned: true,
leading: GestureDetector(
onTap: () => {},
child: const Icon(
Icons.arrow_back,
color: Colors.black,
),
),
flexibleSpace: LayoutBuilder(builder: (context, constraints) {
final fraction =
max(0, constraints.biggest.height - kToolbarHeight) /
(expandedHeight - kToolbarHeight);
return FlexibleSpaceBar(
title: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Row(
children: [
Expanded(
child: Padding(
padding: EdgeInsets.only(left: 24 * (1 - fraction)),
child: const Text.rich(
TextSpan(
text: "Buffet Deal\n",
style: TextStyle(
color: Colors.black, fontSize: 14),
children: [
TextSpan(
text: "Flash Deal",
style: TextStyle(
color: Colors.black, fontSize: 10),
),
]),
),
),
),
const SizedBox(width: 18)
],
),
),
background: Align(
alignment: Alignment.centerRight,
child: Image.network(
"https://source.unsplash.com/random/400x225?sig=1&licors",
),
),
);
}),
expandedHeight: MediaQuery.of(context).size.height * 0.2,
backgroundColor: const Color(0xFFFFF4F4),
),
const SliverToBoxAdapter(child: SizedBox(height: 1000))
],
),
);
}
}
For some reason everything fits perfectly fine on my device but once using it on a smaller device with screen size 5.5" the screen is scrolling and some of the elements or widgets are outside the screen as shown in the images below. I have listed my code below as well.
How can I prevent this from happening and fit everything inside the screen, regardless the size of the screen?
class OtpVerificationScreen extends StatefulWidget {
const OtpVerificationScreen({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() => _OtpVerificationScreen();
}
class _OtpVerificationScreen extends State<OtpVerificationScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.white,
body: SafeArea(
child: Center(
child: Column(
children: [
//Logo
const LogoForAuthScreens(),
const Text(
'Enter verification code',
style: TextStyle(
// fontWeight: FontWeight.bold,
fontSize: 26,
),
),
Container(
margin: const EdgeInsets.only(top: 30, bottom: 20),
child: const Text(
'We send a code to the following number:\n+01723456789',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black45,
),
),
),
Form(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
OtpInputField(),
OtpInputField(),
OtpInputField(),
OtpInputField(),
OtpInputField(),
OtpInputField(),
],
),
),
TextButton(
onPressed: () {},
child: const Text('Resend OTP'),
),
Container(
margin: const EdgeInsets.only(left: 30, top: 30, right: 30),
child: MaterialButton(
onPressed: () {
Navigator.of(context).pushNamed('/signup');
},
color: Colors.red,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
padding:
const EdgeInsets.symmetric(vertical: 20, horizontal: 30),
minWidth: double.infinity,
child: const Text(
'Continue',
style: TextStyle(
color: Colors.white,
),
),
),
),
],
),
),
),
);
}
}
You can wrap each widget inside your column widget with a Flexible widget. This will cause them to resize dynamically based on the available space.
this is two search and dropdown sections I have implemented using animated_custom_dropdown.
I want that "Get Quote Filter " button to place next to the(right side) set location drop down..................................................................................................................................
........................................................................................................................................
import 'package:animated_custom_dropdown/custom_dropdown.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../constants/colors.dart';
const _labelStyle = TextStyle(fontWeight: FontWeight.w600);
class FantomSearch extends StatefulWidget {
const FantomSearch({Key? key}) : super(key: key);
#override
State<FantomSearch> createState() => _FantomSearchState();
}
class _FantomSearchState extends State<FantomSearch> {
final formKey = GlobalKey<FormState>();
final List<String> list = ['Heating', 'Electricians', 'Repair or Service', 'Accessibility Planner'];
final jobRoleFormDropdownCtrl = TextEditingController(),
jobRoleSearchDropdownCtrl = TextEditingController();
#override
void dispose() {
jobRoleFormDropdownCtrl.dispose();
jobRoleSearchDropdownCtrl.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
return Scaffold(
//backgroundColor:AppGreen,
appBar: AppBar(
systemOverlayStyle: SystemUiOverlayStyle.dark.copyWith(
statusBarColor: AppGreen,
),
backgroundColor: AppGreen,
elevation: .10,
),
body: Container(
height: 200,
color: AppGreen,
child: ListView(
padding: const EdgeInsets.all(16.0),
children: [
CustomDropdown.search(
hintText: 'Search Services',
items: list,
controller: jobRoleSearchDropdownCtrl,
fillColor: DarkGreen,
),
const SizedBox(height: 24),
// using form for validation
Form(
key: formKey,
child: Padding(
padding: const EdgeInsets.only(right: 150),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomDropdown(
hintText: 'Set Location',
items: list,
controller: jobRoleFormDropdownCtrl,
excludeSelected: false,
fillColor: DarkGreen,
),
const SizedBox(height: 16),
SizedBox(
child: ElevatedButton(
onPressed: () {
if (!formKey.currentState!.validate()) {
return;
}
},
child: const Text(
'Get Quotes filter',
style: TextStyle(fontWeight: FontWeight.w600),
),
style: ElevatedButton.styleFrom(primary: ContainerGreen),
),
),
],
),
),
),
],
),
),
);
}
}
From your code, I believe that currently "Get quotes filter" showing below to the "Set Location" correct?
If this is the issue, you need to update Column widget to Row which is inside Padding.
Like,
Container(
height: 200,
child: SingleChildScrollView(
child: Column(
children: [
/**/
Row(
children: [
Expanded(
child: CustomDropdown.search(
hintText: 'Search Services',
items: list,
controller: jobRoleSearchDropdownCtrl,
fillColor: DarkGreen,
),
),
Padding(
padding: EdgeInsets.only(left: 15, top: 20, right: 15, bottom: 20),
child: Text(
"cancel"
),
)
],
),
const SizedBox(height: 24),
// using form for validation
Padding(
padding: const EdgeInsets.only(right: 70),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
/**/
Expanded(
child: CustomDropdown(
hintText: 'Set Location',
items: list,
controller: jobRoleFormDropdownCtrl,
excludeSelected: false,
fillColor: DarkGreen,
),
),
const SizedBox(width: 16),
SizedBox(
child: ElevatedButton(
onPressed: () {
if (!formKey.currentState!.validate()) {
return;
}
},
child: const Text(
'Get Quotes filter',
style: TextStyle(fontWeight: FontWeight.w600),
),
style: ElevatedButton.styleFrom(primary: Colors.green),
),
),
],
),
),
],
),
),
)
If this still not worked, please share the expected output and what you are getting now. Because I am not able to compile your code due to custom widgets.
I have updated the color so please update it as per your need. The output is something like,
Hi to Everyone. I am setting position of icon widget. But it is
changing on different device. How can i fix it? thanks in advance.
> -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[for example][1]
import 'package:flutter/material.dart';
import 'package:country_icons/country_icons.dart';
class E_Takvim_Container extends StatefulWidget {
const E_Takvim_Container({Key key}) : super(key: key);
#override
_E_Takvim_ContainerState createState() => _E_Takvim_ContainerState();
}
class _E_Takvim_ContainerState extends State<E_Takvim_Container> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Takvim"),
backgroundColor: Colors.amber,
),
body: IntrinsicHeight(
child: Container(
child: Column(
children: [
Card(
child: Row(
children: [
Container(
width: 30,
height: 30,
margin: EdgeInsets.all(10),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'icons/flags/png/de.png',
package: 'country_icons',
),
),
borderRadius:
BorderRadius.all(Radius.elliptical(300, 900))),
),
Text(
"Tüketici Fiyat Endeksi",
style: TextStyle(fontWeight: FontWeight.bold,fontSize: 17),
),
Padding(
padding: const EdgeInsets.only(left:100.0),
child: Icon(Icons.arrow_forward_ios),
)
],
),
),
],
),
),
),
);
}
}
[1]: https://i.stack.imgur.com/nIzkv.png
For your code example, you can use Expanded for your TextView widget.
Expanded(
flex: 1,
child: Text(
"Tüketici Fiyat Endeksi",
style: TextStyle(fontWeight: FontWeight.bold,fontSize: 17),
),
)
If you want to get the same results at different screen resolutions, (for example: size of widgets or font sizes) You can take a look at the package: ScreenUtils
I am developing this UI in flutter (1st attached picture). Fetching chips from DB and dynamically creating their list. When rendering them on the UI, I am getting overflowed error (2nd attached picture). I want chips to move to the next line if there is no space available. Following is my code:
Container(
padding: EdgeInsets.only(left: 5.0, right: 5.00),
child: Card(
elevation: 4,
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.only(
top: 10.0, bottom: 10.00, left: 10.0, right: 10.00),
child: Column(children: <Widget>[
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
child: Text('Every Month',
style: TextStyle(
fontSize: 14,
color: Color(0xFF0d1b41),
fontFamily: 'Poppins',
fontWeight: FontWeight.bold)),
),
new Container(
child: Text('Every 28th of month',
style: TextStyle(
fontSize: 12,
color: Color(0xFFb1b1b1),
fontFamily: 'Poppins',
fontWeight: FontWeight.bold)),
),
],
),
Column(
children: <Widget>[
new Container(
padding: EdgeInsets.only(
bottom: 20.0,
),
child: Text('Scheduled',
textAlign: TextAlign.right,
style: TextStyle(
fontSize: 12,
color: Color(0xFFfbb450),
fontFamily: 'Poppins',
fontStyle: FontStyle.italic,
)),
),
],
),
],
),
SizedBox(height: 10),
Divider(
color: Colors.grey[500],
thickness: 1.0,
),
Row(children: <Widget>[
Column(
children: <Widget>[
new Container(
width: 60,
height: 70,
padding: EdgeInsets.only(
top: 10.0,
bottom: 40.00,
left: 10.0,
right: 8.00),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
image: DecorationImage(
image: new NetworkImage(
'https://images.unsplash.com/photo-1519125323398-675f0ddb6308?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=94a1e718d89ca60a6337a6008341ca50&auto=format&fit=crop&w=1950&q=80'),
fit: BoxFit.fill,
),
),
),
],
),
Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
width: 220,
child: new Text(
"Coca Cola Zero",
style: new TextStyle(
fontSize: 18.0,
color: Color(0xff8c8c8c),
fontWeight: FontWeight.bold,
fontFamily: 'Poppins'),
textAlign: TextAlign.left,
),
)
],
),
SizedBox(height: 10.0),
generateTags(tagList),
SizedBox(height: 10.0),
]),
]),
])),
],
),
));
static Widget generateTags(List<String> productTagList) {
tagList = productTagList;
return Wrap(
children: tagWidgets.toList(),
);
}
Kindly guide me to create this UI
not exact... but you can modify ...
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
// This makes the visual density adapt to the platform that you run
// the app on. For desktop platforms, the controls will be smaller and
// closer together (more dense) than on mobile platforms.
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var list1 = ["abc", "sdf", "ags", "qwe","eded","ecc","fef","g4g","wev"];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Row(
children: <Widget>[imgWidget(), content()],
),
],
));
}
imgWidget() {
return Container(
height: 40.0,
width: 40.0,
color: Colors.amber,
);
}
content() {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[_title(), _chips(), _actionBtns()],
);
}
_title() {
return Text("CocaCola Zero");
}
_chips() {
return Container(
width: MediaQuery.of(context).size.width-50,
child: Wrap(
children: list1.map((String e) => Chip(label: Text(e))).toList(),
),
);
}
_actionBtns() {
return Row(
children: <Widget>[
_customBTN(icon: Icons.edit, btnName: "Edit", onTap: () {}),
_customBTN(icon: Icons.delete, btnName: "Delete", onTap: () {})
],
);
}
_customBTN({Function onTap, String btnName, IconData icon}) {
return MaterialButton(
child: Row(
children: <Widget>[
Icon(icon),
Text(btnName),
],
),
onPressed: onTap);
}
}
Please use wrap your chips Wrap widget.
class MultiSelectChip extends StatefulWidget {
final List<String> reportList;
final Function(List<String>) onSelectionChanged; // +added
MultiSelectChip(
this.reportList,
{this.onSelectionChanged} // +added
);
#override
_MultiSelectChipState createState() => _MultiSelectChipState();
}
class _MultiSelectChipState extends State<MultiSelectChip> {
// String selectedChoice = "";
List<String> selectedChoices = List();
_buildChoiceList() {
List<Widget> choices = List();
widget.reportList.forEach((item) {
choices.add(Container(
padding: const EdgeInsets.all(2.0),
child: ChoiceChip(
label: Text(item),
selected: selectedChoices.contains(item),
onSelected: (selected) {
setState(() {
selectedChoices.contains(item)
? selectedChoices.remove(item)
: selectedChoices.add(item);
widget.onSelectionChanged(selectedChoices); // +added
});
},
),
));
});
return choices;
}
#override
Widget build(BuildContext context) {
return Wrap(
children: _buildChoiceList(),
);
}
}