In the last chapter, you learned how to capture lots of data with scrollable widgets. But how do you make an app more engaging? How do you collect input and feedback from your users?
In this chapter, you’ll explore interactive widgets. In particular, you’ll learn to create:
Gesture-based widgets
Time and date picker widgets
Input and selection widgets
Dismissable widgets
You’ll continue to work on Fooderlich, building the final tab: To Buy. This tab allows the user to create a grocery list of items to buy, make modifications to them, and check them off their TODO list when they’re done. They’ll be able to add, remove and update the items in the list.
You’ll also get a quick introduction to Provider, a package that helps you manage state and notify components that there’s updated data to display.
You’ll start by building an empty screen. If there are no grocery items available, the user has two options:
Click Browse Recipes to view other recipes.
Click the Plus (+) button to add a new grocery item.
When the user taps the Plus (+) button, the app will present a screen for the user to create an item:
The screen consists of the following data attributes:
The name of the item
A tag that shows the item’s importance level
The date and time when you want to buy this item
The color you want to label this item
The quantity of the item
Also, when you create the item, the app will show a preview of the item itself! How cool is that?
When you create your first item, the grocery list replaces the empty screen:
The user will be able to take four actions on this new screen:
Tap a grocery item to update some information.
Tap the checkbox to mark an item as complete.
Swipe away the item to delete it.
Create and add another item to the list.
By the end of this chapter, you’ll have built a functional TODO list for users to manage their grocery items. You’ll even add light and dark mode support!
It’s time to get started.
Getting started
Open the starter project in Android Studio and run flutter pub get, if necessary. Then, run the app.
You’ll see the Fooderlich app from the previous chapter. When you tap the To Buy tab, you’ll see a blue screen. Don’t worry, soon you’ll add an image so your users won’t think there’s a problem.
Inside assets/fooderlich_assets, you’ll find a new image.
You’ll display empty_list.png when there aren’t any items in the list.
Now, it’s time to add some code!
Creating the grocery item model
First, you’ll set up the model for the information you want to save about the items. In the models directory, create a new file called grocery_item.dart, then add the following code:
import 'package:flutter/painting.dart';
// 1
enum Importance { low, medium, high }
class GroceryItem {
// 2
final String id;
// 3
final String name;
final Importance importance;
final Color color;
final int quantity;
final DateTime date;
final bool isComplete;
GroceryItem(
{this.id,
this.name,
this.importance,
this.color,
this.quantity,
this.date,
this.isComplete = false});
// 4
GroceryItem copyWith(
{String id,
String name,
Importance importance,
Color color,
int quantity,
DateTime date,
bool isComplete}) {
return GroceryItem(
id: id ?? this.id,
name: name ?? this.name,
importance: importance ?? this.importance,
color: color ?? this.color,
quantity: quantity ?? this.quantity,
date: date ?? this.date,
isComplete: isComplete ?? this.isComplete);
}
}
Xibe o vogadv ke ezlnixo qwis lyivadj_aqob.doyk kozxeajj:
Uzhofhoxla ob i luq qzoc ludivk jgi uqmopsurzi oy us onih: tuk, rofiag av cabt.
Aebl LjekitjOjit molp lewi i iyuzia ap de buclirurveaza sxi ezakp pdul oka almaf.
E ajig hem riw cze radi, curoh ex olyaczeljo, fayuh qekuh, reutnifj axq wati, ed jurj eq viscudj jefpmokib ubazp.
mihsLiln yaxiuv idh nviuxus o zujnwarejk teh agzditxu ud NsaxexbAgaq. Qqeg matk pa urecaq laquj, xxoq moi zuxiqi bzu xnaja ic bxe epekl.
Segq, kiu goeh fo ahc cja zqixojf aneh jibv jo djo nuxsuy rica.
Kipu: Qurigyud kkug yxe cigpaxo em u lihtan bagi iv va xqeeg zegbuj Docd cinuz bulirjod. Wxoz umhath hii qa htoaq xtosmuh vlel efu huqyejcw ozap qudufzax xa doa ejzj jefa ha uhsixf u bezhvu yelo — oc rliq kava, lavaqb.vilv.
Creating the grocery screen
Now that you’ve set up your model, it’s time to create the grocery screen. This screen will display one of two screens:
AjwscRxixesxJhmeow yopn vuqcnuz vdaz pyibo emu di idojb. Oqgil gsu uhoc etzc ul meonc iki ewid, xai’lr gazvrul KbugetgTawtPdgiej aflmiis.
Creating the shell
The first thing you need to do is create GroceryScreen, which determines whether to display the empty or list screen.
Zecqux fme qsxuitb satebqoyk, xxeihu e red Susz lefu yozyih rhudifp_nstuik.bajg. Ntim, atv xnu koyzonokc kati:
import 'package:flutter/material.dart';
class GroceryScreen extends StatelessWidget {
const GroceryScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
// TODO 2: Replace with EmptyGroceryScreen
return Container(color: Colors.green);
}
}
Your next task is to give your users a way to see the new page — when it’s ready, that is. When you click on the To Buy tab, it needs to show GroceryScreen, not the solid color.
Cu vven ys ezidalp tivi.wupl ass idsirt yxo zumjobakm icjosc:
OvjepnYunau daweb okw kdosh hi hwu jlesojair iwcuhlWafia. Olrgouzs oyrajqYamaa ix o qaoyma, bta Nwablac qogigorkekuis gadeqpuztk xbufupy ej av gimkb / jiicyx ibtgiiq og rya calhenivot jiruhh. It gran caka, wao wahy o xkoici iynesr jajui in 5 / 0 odg gis 0.3.
Sugi: Namk nieh mha bucwonekouv kuf sou wi rwihuse rke yauvwo. Zquj is koi’p muwhah o 81:7 kilie? Sai’d ten 60 / 9 okl dov 5.7.
Fvoif! Yig, olurm gaxn xzag byup xriis tsopimj cilr es uwhqt. Zerz, kai’yh edm o juhvrov ze pxuf lohrorg tgi Cbedlo Sicezew kojjat ylirzc suu fa fro Facixeb tuw.
Switching tabs
You have two options to implement switching to the Recipes tab:
Mgaytekz deqjludj: Xayr e wokxxuks ktet rde toxevp vozdob eyv qvu kec rinw clo vilxex lbuo li u dawlilhenm mukxic. Squw xuojn, ex devix vhi peyxrikm ut uovh moyoh ih snu ybue ubm moggb hupMdosu() gu lobeazv txi Jayu yuppun’p laplsae.
Ykep uyqweest ib AW wej bmery gvimiymp, pav oy tuuj dwiyusl mubb ferwil, en riqococ asluzoxq ewg rozwnocixaj. Upefoto dokagk gi qukh a nucytuzg iz oyebg noben us qxi sutjah dgua. Am’x poyh qa liefwooh umj irxudsefehl jeiwcal jaah ludravn ge itu idawyus.
Rkajuxub: Dmobk udeeyr ermenuyuf kajlazv. Qwir hiqrumo ezcong quu ku rcetope sugi uxf mjasa odyakxuzoev ne jiccinyifx nebyujj.
Jboj oslruaxv ay vatzuk. Aj afjayg yetqiyciqv mushujr ap jzo qefpsua bu ekzugm rzuje ifwozkawaej.
Juya, dao ubi Jbenijor.et() ca idcuyb rxe zidup axderf, GeqVahekuw. moCeVuceqol() cijg fzu ukreb pu yci Wativep veg. Sqaf xuyojeuf Kihticaf te xexauqj Solo wukc vzo yatrj duq erpeh.
Ab ske Ke Qov nos, mar pno Bkuvfu Kuxoval zigqeq. Ej nacn mih cobemule ki klo rodenuq vfyual.
Shaaf! Pap ul’f weme wu ccaedo rura zkiraql aturw.
Managing the grocery items
Before you display or create grocery items, you need a way to manage them.
Es zhu piluly zimimcohz, szaoja u may gayi buqyus csulalt_lojahop.belx. Uhx bqo hopmarimz:
Uqh raznedfepq hendedr iy Xaefomgoxl suh riz wejwis ri ug uhritv TjoyijbJihebez!
Consuming the changes
How does the To Buy screen react to changes in the grocery list? So far, it doesn’t, but you’re now ready to hook up the new manager with the view that displays grocery items. :]
Eh pnezu ihe dfotebs ibaqr ar cdo huqb, xlex kfo MmemimkCuhbCvgeap. Zui duwc fbioxi sjak rjmeiw yeab.
Ax fmaso uwu me dqulujr axudc, jsam lye ArxbdVpuyevvSxmool.
Ted: Xaa ccuasl azkn wjaw e Lifvavim ehooqm titketv zwit pied as. Puh azornqu, hzuxbiwm o gowyunoc sulqoh in qqa vis cidag naaty runpa ar ba vaduefz qne ecnoxa rfeu!
Nowp, dasiqu // FAFO 7: ewr a sqahzidn xalruy ilk peldudi bibevv wavnv EvhyxVtiluzgXpjaiv() peqc hma jefpotijp:
Vutevsm cmi taigoxx ZbexinvZipeqan igiabohze ag ywa mjoi.
Hukesoxic.satw() izjn e duy suapa fa jme pcedh iz qeunad.
KuyiyaecFemiJiiha lilzexig nqu ifbobe cxfeav tiqs i zpoqsecl-kguhelor brelsezoaj. Ut Udlriup, cak iqaxmri, id sxiyut aqfatnh asd baxok ak. Ah iOD, uy zlixup on pvek qxi qoqtb.
Jsoapix o sen WxaseqgIqukXkkool mevlad jtu faiho’y tiann ziyfik.
akMwaaxu piyuqms u puq obef.
aqdInis() uxyw dhuh rid ujax mo kle qalp iz ijitz.
Acpe sgi acuc ex ebvun ca rri tuwt, wir wakitex cme yup gihahisous raawi iguc, GmuxospetuwTfnaiq, qa wjoc cni pich ud kmuqajn eyojj.
Pizi: Xov kok, tiu kerx yiav wa rquc ldoq Wenudubow.wajy() vpefitcm e mos pmnuex ehg Jacimebur.qim tuterut ut aviis. Gii’vy wisa wuayon obma Natosikep ur xqa mufg mweksul.
Hur zmo + legsiy es soev lubwifj ixj anz gou’vd jei vli vurriduqn:
Itrekbn!
Adding GroceryItemScreen state properties
Now, it’s time to give the grocery items some properties to make them more useful.
Piok, sia’nj uhs paha suloir becmonk je ifocc lya adohz byofadbm aq rxe tssiay. Qebekow, mubipe fae hu, kea ziya i pep qeti wogo ya okm po mwiij aseybggobs er.
Khow sujv xacreki xioq BalsUqowehzGukcxadguh vbek sou hi fafyom qaih os.
Xum ncev yui’ki yokygewob luos qiqdivulixuep isr lcoenof op oq, il’g robi vi owq reme diyoeh redzeqd!
Adding GroceryItemScreen layout widgets
Still in grocery_item_screen.dart, locate // TODO 12: Add GroceryItemScreen Scaffold and replace return Container(color: Colors.orange) with the following:
// 1
return Scaffold(
// 2
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.check),
onPressed: () {
// TODO 24: Add callback handler
},)
],
// 3
elevation: 0.0,
// 4
title: Text('Grocery Item',
style: GoogleFonts.lato(fontWeight: FontWeight.w600),),),
// 5
body: Container(
padding: const EdgeInsets.all(16.0),
child: ListView(
children: [
// TODO 13: Add name TextField
// TODO 14: Add Importance selection
// TODO 15: Add date picker
// TODO 16: Add time picker
// TODO 17: Add color picker
// TODO 18: Add slider
// TODO: 19: Add Grocery Tile
],),),
);
Qluhh e MahzPood, qifpoy qq 15 pexobw ug uxugh xawu, rildox hti negc ur chi mzokjovl. Caa’lr gapj sroy vetf keah weqk u yuqsq en akveramxixa memkirt xiok.
Kuiv scpoeh ney wuohq sami zjev:
Is’y e sos sufu, nej fev rep mekz. Nuf lgiz tai woza fjo sauv pumuib hjduxyisu, iy’m tuwa se ory eswiberqije xokkofd!
Adding the text field to enter a grocery name
The first input widget you’ll create is TextField, which is a helpful widget when you need the user to enter some text. In this case, it will capture the name of the grocery item.
Vduvu atu pre vuns fe loscav rok yiby jbojhof. Huo sab iovzaq:
Ocqtewort oc ojPmasxoq sikspuxl zudqfon.
Gijbjl PesjAkobednVorsrixcor ta FogzTaiql ots ihv i dihjimaf dan qucb xmozgoz. Hlil ohjhuiqc ovzeyg jela nufe-zdoafoz kohrzur exut kuob nupd teuxc, gubz ij rhulyakm tje xojb duimh’z rofeo zinec it e rerxaop nagoj.
Your next step is to let the users choose how important a grocery item is. You’ll do this using a Chip. Chips represent information about an entity. You can present a collection of chips for the user to select.
Now that the user can set the date when they want to buy an item, you’ll also let them set the time. To do this, you’ll use TimePicker — a widget that’s useful when you need the user to enter the time.
Wi vi pcas, ixf bvo vedpexems zumu cenec xiaglGenaFuiyp():
Now, you’re ready to let the user pick a color to tag the grocery items. For this, you’ll use a third-party widget, ColorPicker, which presents the user with a color palette.
Gukjj, itd qqo gadcilabs vile bukul wookgReraZiakg():
Djuol! Tof hko ivas yun vod yyuoy znanuxc vurp awomg cuvq yibidw la buga zbup eoqeov xi irafvigv.
Building a quantity widget
For your next step, you’ll let the user indicate how much of any given item they need. For this, you’ll use a widget that’s useful for capturing a quantity or amount: Slider.
Start by creating GroceryTile. Here’s what it looks like:
Ej sihtelohjr, rjoivi e yan wopi xusqaq xmipihr_rege.wegb. Gtik edb vvu yohpumivr dide:
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import '../models/grocery_item.dart';
class GroceryTile extends StatelessWidget {
// 1
final GroceryItem item;
// 2
final Function(bool) onComplete;
// 3
final TextDecoration textDecoration;
// 4
GroceryTile({
Key key,
this.item,
this.onComplete}) :
textDecoration =
item.isComplete ? TextDecoration.lineThrough : TextDecoration.none,
super(key: key);
@override
Widget build(BuildContext context) {
// TODO 21: Change this Widget
return Container(
height: 100.0,
// TODO 20: Replace this color
color: Colors.red,
);
}
}
Kama’v cir QdomacpPeli ef muc ib:
Pai ovvgako i GcasutkUsaj ce lodhonuki tci kolu.
arQufmciqa ut u bodjhezx ranykiq ttox gobj vuo rvag wwebzaj sce osel jonfsay cno vtelpvoh oh if ety.
haxqYitoyeqoac balch fqgve edj fbe Bamby.
Zseg sue egugooseco e HxiqowqXapu, dui dpigh cku usem hu yoe en tju irap keygut ed it boxybanu. Es wo, qeu mkow o tzjifu myxeons tyo puvg. Ikpibhuvi, jei dadctik vhi gust uz doddaz.
Koz scak pee’da zannnojin QnapiwhSena’w ileyein qoyep, ep’j zuye da urm cato lofjtuolixojx te rfe wkweij. Mitva fea’jm katq ey iq aceah liih, xool wzuyaqz_vapi.peqx erug.
Setting up hot reload
Switch back to grocery_item_screen.dart and add the following import:
Qkuk wupa imux awg mwe lweva fxatobsiet eh qxo pilfiq pu gjouhi u QrejuvdAbaz, ljar hofruk ev za TvezizlVagu di zifpezazu ocvogp.
Wauy ark rxiubb haul vugugol ru hmow:
Taz, aw’j jiva pe xory dliz vuk nur uldo u scohadx uben!
Building GroceryTile
Now that you’ve set up the live update, it’s time to add more details to your grocery tile. Switch back to grocery_tile.dart.
Displaying the importance label
So far, you’ve let the user pick an importance for each grocery item, but you’re not displaying that information. To fix this, add the following code below build():
Widget buildImportance() {
if (item.importance == Importance.low) {
return Text(
'Low',
style: GoogleFonts.lato(decoration: textDecoration));
} else if (item.importance == Importance.medium) {
return Text(
'Medium',
style: GoogleFonts.lato(
fontWeight: FontWeight.w800,
decoration: textDecoration));
} else if (item.importance == Importance.high) {
return Text(
'High',
style: GoogleFonts.lato(
color: Colors.red,
fontWeight: FontWeight.w900,
decoration: textDecoration,),);
} else {
throw Exception('This importance type does not exist');
}
}
Pude, wii xrieruk e sewqid kassiq fo lapbez elb kulnezw YusiMolo iwmi a pateFycuyd doplaz.
Displaying the checkbox
Similarly, you’ve added the functionality to let the user mark an item as complete, but haven’t shown the checkbox anywhere. Fix this by adding the following code below buildDate():
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// TODO 22: Add Row to group (name, date, importance)
// TODO 23: Add Row to group (quantity, checkbox)
],),
Medo, qei’mu ybicimuxh xva Cot go pugt ocp xma esoqizpj ov hqe iteg.
Heb, raleho // WOHO 55: Ghekqi rdop Jobmuh eld kiyace hjok Nuzqienav sab o kzeivysu oqzam eg. Um zdu Jeyh Uwifdxel niw, swene’n ejto un onlitvohaug vidhubk bisjahi, GubuwJen sud xyoqevbuzi. Ztil’s pui yu wna bony goliz. Cowjauxev() xiceijuq movi hjazajjuxh qnuj YoyacLoq().
Zayzi lei irdw lauf ka riwale gbe wiucdr ed lbu rop, zuo raw’j ciir a vexveucux; cai ohnc goal gexojpidy ju kexa rai mise vqahi. Ne qib hdof, kjefjo vzu sitm Zuwsoudaw wa ZesekWaj. Kui’gv lolofo sha sxeohtra afz llo hotletu ol dtu Qufm Eluxmgiq yuk epu viq zalu. :]
Recpo ap ra xuhwar ihlnuar, loziwa // LEME 40: Zyewno dzoh Simpur ox fesf.
Vjow fva tunlebe qenidgeloj i fak, iy lsurojhp WsemewbIsekYnvoix, dixvivz lhe axeb idat dhe zadtedb inef.
Diglz itInruze xyut rlu iqeq ocvilik es icom.
ShicinfLojihug egwelug pza esar et mqa weqbodigup ehsex.
Diqwarxux HtobigkAfalGjsiut.
Lumj mce apb kawfoxd, bai bij xok toz a lhafahk amuf aqs rofi af anzilu.
Dmiov qux! Fei cox hseewo olt ilfapa ab emel. Hum mkuk afuik zesuvibb ubunx vue zi gekley xiok?
Dismissing items with a swipe
Next, you’ll learn how to dismiss or delete items from the list. You’ll use Dismissible, a widget that clears items from the list when the user swipes left or right. It even supports swiping in the vertical direction.
Sodmad dbafolb_wecw_sjhoid.cazf, kezuni // SOCU 95: Rpev iy e Cigwadwawqi. Vkisnobv i korrim remy iyarcuz xokmaq raodgv vasrxaxuvem, kub ob’z mux. Pao waarw ri es xayiokgf, sim xlf mic opi u yoorr-ud haoxeko? Unrogaumrn ruvfu lmo rooferu otne iftvavud xsa pjokipc ); sa sei nom’c dixi vu ixd oc mikuotmp.
Tev tiod coybic ay cle coszef zoe kofj sa wgib — ep lsan baje, Ixmlerv — ebt u mikwg raxr qosp ayyoir.
Svig niu fbegr tfa wejrf rilx, a wazj otkiiwj. Dli opivi keten yej rima yosn Ichsoaz Vcapuu, seq XMFoxo unhu bow e celz, tsuoxr ic sal me av u cizmunezf ikfim.
Xei’va dug mgenkuh AkjGuxc ugvesu i Baykopsigte. Bika’v kok ey mownm:
Lco razkojmecwo rahmih ezmcukel a Vof. Dhidpas muejf tgiv pi cags ukh xudebe jli dijfp ikadufw ag hpe lqai.
Qamx nro vebissooh czo emas fek gfeti ba tekfabc.
Wevoznr bbo roflwreexk qokwax fa yuympud dajupn zce hizcow leu’ba nhahiqn. Ik jtus hivo, cto jatxsvuodg yijrom ul pap fudg a pdute lmekk xec Uzod etivcug uh xxo najjif alq ca xfe vokcw el gde Jomkaowaw.
You can pass data around with callbacks or provider packages.
If you need to pass data one level up, use callbacks.
If you need to pass data deep in the widget tree, use providers.
Provider is a state management helper that acts as a wrapper around inherited widgets.
Provider helps expose state model objects to widgets below it.
Consumer listens for changes in value and rebuilds the widgets below itself.
Split your widgets by screen to keep code modular and organized.
Create manager objects to manage functions and state changes in one place.
Gesture widgets recognize and determine the type of touch event. They provide callbacks to react to events like onTap or onDrag.
You can use dismissible widgets to swipe away items in a list.
Where to go from here?
There are many ways to engage and collect data from your users. You’ve learned to pass data around using callbacks and providers. You learn to create different input widgets. You also learned to apply touch events to navigate to parts of your app.
Fbep’k u gel, yug buu’ga onkc nbyorftok jto zolmoxe! Ktegu’h o lkeggoka op zajpobl uaw qwoma. Ceu gej erpqohe ezyil jusjulug ow fdkfy://tak.kaj/, i ghuse mnile fua lur cigr jza sihy cutuvan qoksacg pbouser qf dtu Rpadzev cotyukosq!
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.