1
1
import 'package:flutter/material.dart' ;
2
2
import 'package:chips_choice/chips_choice.dart' ;
3
+ import 'package:async/async.dart' ;
4
+ import 'package:dio/dio.dart' ;
3
5
4
6
void main () => runApp (MyApp ());
5
7
@@ -34,6 +36,22 @@ class _MyHomePageState extends State<MyHomePage> {
34
36
'Science' ,
35
37
];
36
38
39
+ String user;
40
+ final usersMemoizer = AsyncMemoizer <List <ChipsChoiceOption <String >>>();
41
+
42
+ Future <List <ChipsChoiceOption <String >>> getUsers () async {
43
+ String url = "https://randomuser.me/api/?inc=gender,name,nat,picture,email&results=25" ;
44
+ Response res = await Dio ().get (url);
45
+ return ChipsChoiceOption .listFrom <String , dynamic >(
46
+ source: res.data['results' ],
47
+ value: (index, item) => item['email' ],
48
+ label: (index, item) => item['name' ]['first' ] + ' ' + item['name' ]['last' ],
49
+ avatar: (index, item) => CircleAvatar (
50
+ backgroundImage: NetworkImage (item['picture' ]['thumbnail' ]),
51
+ ),
52
+ )..insert (0 , ChipsChoiceOption <String >(value: 'all' , label: 'All' ));
53
+ }
54
+
37
55
@override
38
56
Widget build (BuildContext context) {
39
57
return Scaffold (
@@ -100,7 +118,7 @@ class _MyHomePageState extends State<MyHomePage> {
100
118
),
101
119
),
102
120
Content (
103
- title: 'Disabled Choice item ' ,
121
+ title: 'Disabled Choice Item ' ,
104
122
child: ChipsChoice <int >.single (
105
123
value: tag,
106
124
options: ChipsChoiceOption .listFrom <int , String >(
@@ -114,7 +132,7 @@ class _MyHomePageState extends State<MyHomePage> {
114
132
),
115
133
),
116
134
Content (
117
- title: 'Hidden Choice item ' ,
135
+ title: 'Hidden Choice Item ' ,
118
136
child: ChipsChoice <String >.multiple (
119
137
value: tags,
120
138
options: ChipsChoiceOption .listFrom <String , String >(
@@ -128,19 +146,146 @@ class _MyHomePageState extends State<MyHomePage> {
128
146
),
129
147
),
130
148
Content (
131
- title: 'Custom Choice item' ,
149
+ title: 'Append an Item to Options' ,
150
+ child: ChipsChoice <int >.single (
151
+ value: tag,
152
+ options: ChipsChoiceOption .listFrom <int , String >(
153
+ source: options,
154
+ value: (i, v) => i,
155
+ label: (i, v) => v,
156
+ )..insert (0 , ChipsChoiceOption <int >(value: - 1 , label: 'All' )),
157
+ onChanged: (val) => setState (() => tag = val),
158
+ ),
159
+ ),
160
+ Content (
161
+ title: 'Selected without Checkmark and Brightness Dark' ,
162
+ child: ChipsChoice <int >.single (
163
+ value: tag,
164
+ onChanged: (val) => setState (() => tag = val),
165
+ options: ChipsChoiceOption .listFrom <int , String >(
166
+ source: options,
167
+ value: (i, v) => i,
168
+ label: (i, v) => v,
169
+ )..insert (0 , ChipsChoiceOption <int >(value: - 1 , label: 'All' )),
170
+ itemConfig: const ChipsChoiceItemConfig (
171
+ showCheckmark: false ,
172
+ selectedBrightness: Brightness .dark,
173
+ // unselectedBrightness: Brightness.dark,
174
+ ),
175
+ ),
176
+ ),
177
+ Content (
178
+ title: 'Async Options and Brightness Dark' ,
179
+ child: FutureBuilder <List <ChipsChoiceOption <String >>>(
180
+ initialData: [],
181
+ future: usersMemoizer.runOnce (getUsers),
182
+ builder: (context, snapshot) {
183
+ if (snapshot.connectionState == ConnectionState .waiting) {
184
+ return Padding (
185
+ padding: const EdgeInsets .all (20 ),
186
+ child: Center (
187
+ child: SizedBox (
188
+ width: 20 ,
189
+ height: 20 ,
190
+ child: CircularProgressIndicator (
191
+ strokeWidth: 2 ,
192
+ )
193
+ ),
194
+ ),
195
+ );
196
+ } else {
197
+ if (! snapshot.hasError) {
198
+ return ChipsChoice <String >.single (
199
+ value: user,
200
+ options: snapshot.data,
201
+ onChanged: (val) => setState (() => user = val),
202
+ itemConfig: ChipsChoiceItemConfig (
203
+ selectedColor: Colors .green,
204
+ unselectedColor: Colors .blueGrey,
205
+ selectedBrightness: Brightness .dark,
206
+ unselectedBrightness: Brightness .dark,
207
+ showCheckmark: false ,
208
+ ),
209
+ );
210
+ } else {
211
+ return Container (
212
+ padding: const EdgeInsets .all (25 ),
213
+ child: Text (
214
+ snapshot.error.toString (),
215
+ style: const TextStyle (color: Colors .red),
216
+ ),
217
+ );
218
+ }
219
+ }
220
+ },
221
+ ),
222
+ ),
223
+ Content (
224
+ title: 'Works with FormField and Validator' ,
225
+ child: FormField <List <String >>(
226
+ autovalidate: true ,
227
+ initialValue: tags,
228
+ validator: (value) {
229
+ if (value.isEmpty) {
230
+ return 'Please select some categories' ;
231
+ }
232
+ if (value.length > 5 ) {
233
+ return "Can't select more than 5 categories" ;
234
+ }
235
+ return null ;
236
+ },
237
+ builder: (state) {
238
+ return Column (
239
+ children: < Widget > [
240
+ Container (
241
+ alignment: Alignment .centerLeft,
242
+ child: ChipsChoice <String >.multiple (
243
+ value: state.value,
244
+ options: ChipsChoiceOption .listFrom <String , String >(
245
+ source: options,
246
+ value: (i, v) => v,
247
+ label: (i, v) => v,
248
+ ),
249
+ onChanged: (val) => state.didChange (val),
250
+ itemConfig: ChipsChoiceItemConfig (
251
+ selectedColor: Colors .indigo,
252
+ selectedBrightness: Brightness .dark,
253
+ unselectedColor: Colors .indigo,
254
+ unselectedBorderOpacity: .3 ,
255
+ ),
256
+ isWrapped: true ,
257
+ ),
258
+ ),
259
+ Container (
260
+ padding: EdgeInsets .fromLTRB (15 , 0 , 15 , 15 ),
261
+ alignment: Alignment .centerLeft,
262
+ child: Text (
263
+ state.errorText ?? state.value.length.toString () + '/5 selected' ,
264
+ style: TextStyle (
265
+ color: state.hasError
266
+ ? Colors .redAccent
267
+ : Colors .green
268
+ ),
269
+ )
270
+ )
271
+ ],
272
+ );
273
+ },
274
+ ),
275
+ ),
276
+ Content (
277
+ title: 'Custom Choice Widget' ,
132
278
child: ChipsChoice <String >.multiple (
133
279
value: tags,
134
280
options: ChipsChoiceOption .listFrom <String , String >(
135
281
source: options,
136
282
value: (i, v) => v,
137
283
label: (i, v) => v,
138
284
),
139
- itemBuilder: (item, selected, onSelect ) {
140
- return CustomChip (item.value, item. label, selected, onSelect );
285
+ itemBuilder: (item, selected, select ) {
286
+ return CustomChip (item.label, selected, select );
141
287
},
142
288
onChanged: (val) => setState (() => tags = val),
143
- isWrapped: true ,
144
289
),
145
290
),
146
291
],
@@ -149,15 +294,13 @@ class _MyHomePageState extends State<MyHomePage> {
149
294
}
150
295
}
151
296
152
- class CustomChip < T > extends StatelessWidget {
297
+ class CustomChip extends StatelessWidget {
153
298
154
- final T value;
155
299
final String label;
156
300
final bool selected;
157
- final Function (T value, bool selected) onSelect;
301
+ final Function (bool selected) onSelect;
158
302
159
303
CustomChip (
160
- this .value,
161
304
this .label,
162
305
this .selected,
163
306
this .onSelect,
@@ -167,28 +310,50 @@ class CustomChip<T> extends StatelessWidget {
167
310
@override
168
311
Widget build (BuildContext context) {
169
312
return AnimatedContainer (
170
- margin: EdgeInsets .symmetric (vertical: 5 ),
313
+ height: 100 ,
314
+ width: 70 ,
315
+ margin: EdgeInsets .symmetric (
316
+ vertical: 15 ,
317
+ horizontal: 5 ,
318
+ ),
171
319
duration: Duration (milliseconds: 300 ),
172
320
decoration: BoxDecoration (
173
321
color: selected ? Colors .green : Colors .transparent,
322
+ borderRadius: BorderRadius .circular (15 ),
174
323
border: Border .all (
175
324
color: selected ? Colors .green : Colors .grey,
176
325
width: 1 ,
177
326
),
178
327
),
179
328
child: InkWell (
180
- onTap: () => onSelect (value, ! selected),
181
- child: Padding (
182
- padding: EdgeInsets .symmetric (
183
- vertical: 7 ,
184
- horizontal: 9 ,
185
- ),
186
- child: Text (
187
- label,
188
- style: TextStyle (
189
- color: selected ? Colors .white : Colors .black45,
329
+ onTap: () => onSelect (! selected),
330
+ child: Stack (
331
+ alignment: Alignment .center,
332
+ children: < Widget > [
333
+ Visibility (
334
+ visible: selected,
335
+ child: Icon (
336
+ Icons .check_circle_outline,
337
+ color: Colors .white,
338
+ size: 32 ,
339
+ )
190
340
),
191
- ),
341
+ Positioned (
342
+ left: 9 ,
343
+ right: 9 ,
344
+ bottom: 7 ,
345
+ child: Container (
346
+ child: Text (
347
+ label,
348
+ maxLines: 1 ,
349
+ overflow: TextOverflow .ellipsis,
350
+ style: TextStyle (
351
+ color: selected ? Colors .white : Colors .black45,
352
+ ),
353
+ ),
354
+ ),
355
+ ),
356
+ ],
192
357
),
193
358
),
194
359
);
@@ -244,7 +409,7 @@ void _about(BuildContext context) {
244
409
ListTile (
245
410
title: Text (
246
411
'chips_choice' ,
247
- style: Theme .of (context).textTheme.headline.merge ( TextStyle ( color: Colors .black87) ),
412
+ style: Theme .of (context).textTheme.headline.copyWith ( color: Colors .black87),
248
413
),
249
414
subtitle: Text ('by davigmacode' ),
250
415
trailing: IconButton (
@@ -261,13 +426,13 @@ void _about(BuildContext context) {
261
426
children: < Widget > [
262
427
Text (
263
428
'Easy way to provide a single or multiple choice chips.' ,
264
- style: Theme .of (context).textTheme.body1.merge ( TextStyle ( color: Colors .black54) ),
429
+ style: Theme .of (context).textTheme.body1.copyWith ( color: Colors .black54),
265
430
),
266
431
Container (height: 15 ),
267
432
],
268
433
),
269
434
),
270
- )
435
+ ),
271
436
],
272
437
),
273
438
),
0 commit comments