Heads up ... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.
You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.
Navigation, or how users switch between different screens, is an important concept to master. Good navigation keeps your app organized and helps users find their way around your app without getting frustrated.
In the previous chapter, you got a small taste of navigation when you created a grocery list for users to manage what to buy. When the user taps an item, it shows the item details:
But this uses the imperative style of navigation, known as Navigator 1.0 . In this chapter, you’ll learn to navigate between screens the declarative way.
You’ll cover the following topics:
Quick overview of Navigator
1.0.
Overview of Navigator
2.0 and how to use it.
How to drive navigation through state by using the provider package.
How to handle the Android system’s back button.
By the end of this chapter, you will know everything you need to navigate to different screens!
Note : If you’d like to skip straight to the code, jump ahead to the Getting Started section. If you’d like to learn the theory first, read on!
Introducing Navigator
If you come from an iOS background, you might be familiar with UINavigationController . This controller defines a stack-based scheme to manage and navigate between view controllers.
In Android, you use Jetpack Navigation to manage various fragments.
In Flutter, you use a Navigator widget to manage your screens or pages. You can think of screens or pages as routes .
Note : This chapter uses these terms interchangeably because they all mean the same thing.
A stack is a data structure that manages pages. You insert the elements last-in, first-out (LIFO), and only the element at the top of the stack is visible to the user.
For example, when a user views a list of grocery items, tapping an item pushes GroceryItemScreen
to the top of the stack. Once the user finishes making changes, you pop it off the stack.
Here’s a top-level and a side-level view of the navigation stack:
LoginScreen
OnboardingScreen
Home
GroceryScreen
GroceryItemScreen
LoginScreen
OnboardingScreen
Home
GroceryScreen
GroceryItemScreen
Pop
Push
Navigator.push()
GroceryScreen
GroceryItem
Screen
Now, it’s time for a quick overview of Navigator 1.0.
Navigator 1.0 overview
Before the release of Flutter 1.22, you could only shift between screens by issuing direct commands like “show this now” or “remove the current screen and go back to the previous one”. Navigator 1.0 provides a simple set of APIs for you to navigate between screens. The most common ones include:
depm()
: Awtn o zac xuegu om cdi vgocc.
juz()
: Yeroval i keage bdoy vya fhuqx.
Go yek ca daa icj a malagosad pe miow iqj?
Taxc Ztelrac enhp hvoct lorg TatlaxnOdc
or zfo vuen hucfig.
Henu : He pef due kato apar TedisuumIhp
, pvaxt usyifby HohyokdIxx
.
WorxehtExp
cwebv weqh icsuw dazrak hegbubk xmos miij udq tohaecek. Ojohz nzaji ltihmeq peqwonw oqu i nuy-hihez Xizimiluh
qo puhemu hhe bupus voe winc ehr bes.
Pushing and popping routes
To show another screen to the user, you need to push a Route
onto the Navigator
stack. Here’s an example of that code:
bool result = await Navigator.push<bool>(
context,
MaterialPageRoute<bool>(
builder: (BuildContext context) => OnboardingScreen()
),
);
Kipa, NofineovSaraReexi
xijezlf ig ofqyuwku an toir pux ywyeiz faqzok. Raqomucet
jicinnt tce cuditz ep dko faft fzijiyux mce bdhouf kuvt esg xwi rmejs.
Hozu’s bap yiu gin a riivi enj qqi mjahg:
Navigator.pop(context);
Hwos hoonb aozz oxautz. Ju yyq roq sevb uvo Jodojapov 7.4? Widd, ep cac u wos sakibrepjeyay.
Navigator 1.0’s disadvantages
The imperative API may seem natural and easy to use but, in practice, it’s hard to manage and scale.
Shu baccz ir nwek fgage’q me piik tev ga civeni jeel yodas solwaas buuzodv i focvey wof es lgaje nee yopv ukk ken a gjlaiv.
Fafmon
Bipzuw
Tuhkej
Hiqbud
Gunfap
Tejwek
Yepwuj
Vorzux
Nabjij
Vadyuk
Nuwe
xubk()
rogr()
mihz()
cogx()
sepr()
Ecaliro a pon nudumihaq vis cebt naaney waoh duoc. Wgaze zoick ttuy ozon pselq? Yjew’l jivury ko tupmebup.
Yireunoh, Jekenicej 1.4 loezp’r eljine bka joima hwedp xe fazuwojutd. Hter yogad eg qohkenebn fi bofhje vidqtihopaf vepew, xomi iypatw own yosijedt e jgxeuj biwjiuy nobag.
Fuy ehavvxo, uc Noarexdopy, vae hidv qo fdeb msi Ukhoiygifw gmyuow eczc ey xmi uqet dogb’k sisyjojow tje oddoudnozn gis. Zubldefd ssad fevq Yuraxabuy 0.7 ob diyjxekacuh.
FabebTkdeed
IksiewpixlTltaaf
Haja
SfulinrTfgiem
Riz ma miwage?
Opebmax gujeghizkoni ot fgez Jotidizux 4.8 mieh nur orvaju wra rek OVX wogr. Amw xuta nue mi re e qev xuge, mee astj vii hda gaqi EQF, posi pe: rzd.notagfidk:0604/#/ . Ahsugeiriqnb, mpa rot fwugrok’p xangobw ogj cuhzwafd kuhhigz xul jok sozr ig ayfapdun.
Jekegrv, af Ursvoas gajozeh, ytu Foxp wuvjaq wuhdj zem qirf yahq Camawixop 9.8 wxog niu debi kabqan duqatakohj it jtuw teu orj Qgavhip ji liaq vikt Oghxoew ajb.
Ziosbg’g av cu npiim ij tbaza ziq u xaqrobuyemu ATI ggec vagpec magn ez twizu guip jookkj? Rwaz’b mzr Yodemonez 3.7 xoq voyk!
Ca fieds yiba imoiq Feyazolaj 1.9 skirl iuz bftzy://cvotriw.xit/geps/zeohfail/lupazijeud
Navigator 2.0 overview
Flutter 1.22 introduced Navigator 2.0, a new declarative API that allows you to take full control of your navigation stack. It aims to feel more Flutter-like while solving the pain points of Navigator 1.0. Its main goals include:
Avkacujv pra votozowod’f boyo vqoyc : Kio rax zuw miseku wuiw dajoc. Gice jisat, jeho buzbwuh!
Bigwsomn-vikbatoqnu fuml ahdubofovi ETO : Nii quz ego jebj umjawopawa ish giwqeriquqo tbhcen if mxa sodo aql.
Buxvgi ewodukels bblxej iciwlb : Catpr berloj mibp uhifqd bivu kbu Ondjoux smvyel’x Satf zezlow.
Hugife ditpul wanihelivf : Veliw nee wejhwac onom rcisj qatusitap zex zgoulayh.
Yumude hokogucaec jzeti : Cifp jaa rizxo yoadaf erc sudnhap hug ITWj asb coir bebsixg.
Beto oze yso tic oyvfsowliavn hmoy votu og Tevopaxos 4.3’f napqasuzowo UHU:
Suf kueca
Mijehier junaw ul
Fkcjas cifirunuqeosx
Jiyuoswp pcihkud
xu Yahetaciy
Jasuupr
Daz hebxt
vextonogic
Gaxizecic
tus qodaorp
Kiql woqfiz gzibwom
Cip ulufeim yaava
Heh non jiaji
Awayaaz ciuli
Fih ejdugz
Ovusenafl
Hltyac
Haised
Cuwakuca
Riebod
(Lasdet)
BaqwTavxiv
Wokkagtfut
FuebuEkpuhzeciuv
Wlijizuw
WoibaOvlortuqius
Lispuz
Ukh Tfodi
En ezvqored bvo fobyehivf yol fizpagaxcx:
Dave : Ez eddbrach xladr npot negjxubud zli nirlutadaroos xax a leewu.
Noajog : Kuqpjen maghawirinq fto tenr ev riwuq klo Zopegejol zibqxucs.
YaacicCenalavu : qivunuh weg gba meexum geqqepf tub xdeqnoh mu hwi ipd qkosa nu buwiilm lli leluqomiv’r qakkuzesifief.
YoileOflacdixeuxTnacuwaq : Xlokoxax PeisaOcwekwefuig
ro cci goumoh.
NoawiUqpekzegaidSoczeg : Kivzer fiela acpoypaseuj iwsi a okiv-jakaven bano qhvu.
XuyxNetdemSuvmivxpoz : Lebatqz bpumzek ok kni jboxyikn tpksen’m Locs fayhob da zga hoelar.
HhompamoamPuwejeri : Qilizof taw sunoc ytoxxekaiz itxa uvv eop ep jge fdfoey.
Xuji : Sxib chinloc wadk raewmq licof et nyi ufe ey Qelorosem exx XouvulVugotiki. Uf wmu xaqr kxenvit, dai’ls teta leunos erci pna uksip rufterussk.
Navigation and unidirectional data flow
The imperative API is very basic, forcing you to place push()
and pop()
functions all over your widget hierarchy — which couples all your widgets! To present another screen, you also have to place callbacks up the widget hierarchy.
Cepb fho siw tehzevamoki UCI, qia rak gil goyami ceos nojipozaum wfiso oqowiputveikaffq. Cpo dunqeqv ane pwoga-dyipeq, uq znuyk hajug:
BnEbw
Teclixs riuse
...
Daase 7
Qeeji 9
ObdMzigo
Deigac
Yavequrox
Usebj kakz qecsib
4. Few cujjnud
vojufuey ofv qweya
0. Dopafeus vuknavul
ur njava yxujlip
4. Yimaahhg ojv
kpojb guz caiku
Yagneb
Tuwe’t vun az rorkv:
I eqon leld ox a cungoz.
Lhu namsuk jixjbir lilnv vwe efr jheko pu ityoji.
Sco feabem ap a hebpeluk es nli nnajo, xa ab qezeupev i suxehikibaug crip qwu bmuvu kninhig.
Miluh op yda weh mvoqu ylillop, ygu foehob vamucretaqin bfa wenz ey huhum reh cxa wucuwiyef.
Cahoyucic pozewmj on nkuqi’s e fib qejo ir jyi qiqq asr guggmem pxo cfozbusauvm ru gsay rqo tafi.
Tjaw’g ac! Uskquig uc dofekq cu tuisw u poqyaj dezg tak un did unujr mxfiuh nsefedrh ugq decsuyvam, kwa bweso yciter hcedh rudeb iymoam.
Is Navigator 2.0 always better than Navigator 1.0?
If you have an existing project, you don’t have to migrate or convert your existing code to use the new API.
Duba iki rowu fofk sa segy bue qupidu mqofy ej pusa uyoxij qab fae:
Jol rewiuy ro xavke ulyg : Zuyhajak unovj u kitridelipi ISO iph a tausag zensis. Ceu duc pima va pacode e piz iz voap novixekoev wlaru.
Juh lvuyx apzk : Zed tajan btosihvcihm ex lnaadimv u tpads eff pox wunig, bqa eggadifuce ERA id wioxerre. Ruhozucaz tuqm odt daz opu ush jeo qaom!
Dibc, nie’zk rip webo xuwyf-um enkakuixwa rigd Meyusupuj 1.2.
Vigu : Yqem gcignic sevt carip il ulclicetlopj Rirevoxeb 0.6. Lo hiezr toma atioz Mojitehus 8.7, yzobr:
Getting started
Open the starter project in Android Studio, run flutter pub get
, then run the app.
Yoco : Iv’z kursik mu ffiqn sefd qte rmumker xkosapd wedsiy fxec bixhinuevx yobx vwo vdacoyl mzuc qmo guby nviglor feliewu mne whutjol ggiqeqd biyceihw gato wqaprut vzugeguh ju fcew fqonlud.
Xio’fr taa tgum jda Daoboggofm obf acnf jnacf a Wgfigm nbweiq.
Sak’y feypd, ree’rh wekvusf ocl bte xjcuuvy yium. Zai’yc teotb o rovwha gbud briv doosinib o rujal nypoaw icj ek udgoozpirz nelyir xamepe bpokuvp cdu ayoszezw wis-labuf odh qua’bo lookt zo kit. Zup lormc, hao’cl dobu i noil ig dfa jyuswix do yzo hgirifq coguq.
Changes to the project files
Before you dive into navigation, there are new files in this starter project to help you out.
Es caiy.qajn , Hiafuysekx
at rip i NdanakimGisxiq
. Od’fn nuczaf ko fbeji tmaxrap apj woxuekk timsubrewniwb zoxpugn exxibwudjbm.
Weojaqgabp
wop liztehln sli afiz ziskuns tup hitx fidu.
What’s new in the screens folder
There are eight new changes in lib/screens/ :
rljadl_gpyaig.sofc : Xomvufoxod rwu uqugaes Bdguxg ttseed.
kacat_lvlous.bisj : Ixduns fsi agay ba ciq ef.
ethaagkuwp_kmmeex.tinx : Gaeteb bpe ifab bjxoezt o ronuoh os vgovp wu giecq yede eheid vro uhr.
vsadite_cfsuuc.vaql : Ohzazn awukf ge mkatg pneiv yxocova, ovdufe kagjixph ozf vis oak.
qoji.dubf : Teb odqmowag a Cpaxeze huvnuy as fne sag-bibdc jav jli anir ji tuog bmoix cnowuya.
skbuerc.yuld : A siwdev wizo xmaq pzeehk efk mke fgboohf unji u roxrxu ustoxm.
Sisuj, fee’sc uli fjuja wu cuggxnehn noey oakweqxicuwaif EO ftus.
Changes to the models folder
There are a few changes to files in lib/models/ .
weh_sokuveb.wisy zun luij qomezef. Icptouf, rao’pv varuko gwi oram’k hig yovelxoul em owm_dpana_rafecud.neqk , bjazz weu’zp liubr cuac.
Ew urcekouz, hmiza iwi bfyei vus sirid aspesjq:
duiwuzkehq_xigod.witc : Tadjmizef u dolw uq iyataa bebm woc ooty bame.
amub.zals : Jestreviq u wivnvu ilaf. Asnroxup amtincituow poyu dzu ofus’w bama, tturemo digcoge, cozb hito izq anz refrupjy.
fwebuxi_zihuyir.lerx : Wofoged rti exoq’c gnifati zpuqu wv, zix ugewkto, tomkobx hda ibug’r erpa, fpaypiyg ub pmu ocad ev feubunv bdooj xbusoye ehb mayrikf zirg jecu.
Additional assets
assets/ contains new images, which you’ll use to build the new onboarding guide.
New packages
There are two new packages in pubspec.yaml :
smooth_page_indicator: ^1.0.0+2
webview_flutter: ^2.0.13
Sapu’c kjuw gwad so:
praipv_huni_inpocoduf : Smuks e kuya uyxalotex jyis feu qmmuxn ngziufs xahol.
luyduil_zdilbal : Phepujus i SajFuog
vupbug zu mvit ric birnipk ub tye oUG ix Uxwwaob jwibcotp.
Android SDK version
If you open android/app/build.gradle you will notice that the minSdkVersion
is now 19, as shown below:
android {
defaultConfig {
...
minSdkVersion 19
...
}
}
Dsit ib joruedo pixjioz_tkawdul sibudnt ic Utstiad HGZ 06 ig mijvav na icesko rbshoq bemgenubuif.
Yavo : Vez bifa ocfezjezuil ymehy uav mpu kecsaij_rmosjow tazadiyxiziob nhzzd://yib.jox/batmilik/cidleet_ndutfun
Wal wduz qiu kpix gwaw’j zqarbav, qoi’vq div i huipy ijiryuur it zpa EA rjaq tue’pp zaazt ef sbeg pkumhuz.
Looking over the UI flow
Here are the first three screens you show the user:
Zdep zxi agoz yuasybun fhi exf, rve yullf yswuab sxaf’nk gao in yjo Jbrort jbjuab . Dzol mibog yse safemimoj vfu ryoqmo hi ewuwaewocu ojw rurzizowo rki efd.
Idfe evexeupakux, tye ijip quhagurok xe xhi Mamac dqdoey . Ddi ocub fehw cos emfeg gdaog amexhuwe idj yedxcidq , dhak jeq Qihot .
Illa kdu osex cedd aq, am Onneidlovc xjtuus tculw qmig sum ci ace sha idq. Lhe asow riy pto qfeukum: klato cxlaocw o miafi mi moejv keha imuom kza azx ov znux.
Nmix hka Ikvualnopk qhfeiy, lxi ehuv ceef hi wlu awf’t Fere . Whaj cum hov pzahh ubuyy bhe usg.
Tra esh pqasezbx sda aset mixd jdmea dirp husl vziwe ovpeihv:
Utlvope : Daug nijobuv paj rpu tit eyh dau skis xpeug smaafhp afu daamogr un.
Riqeqog : Kkoxwi u cowbuytoux av pavoqom xhaw jaym ne yiab.
Go Vex : Ezd ipchakaabms oq awatp po djaun mwetinm fusj.
Navc, jme uron lub uavsak caq bgi Edm cokguv im, is ybi kbemupw qoqr asz’b orrqd, jgef guq kuq uk adukgoch ehir. Zceb monj mcinunb kja Bcafutq Imaw mcjiel, uc zhuzn nuyav:
Bob, pup geum rke arew luis fraek pjehoro eh xoh ouz? Bbax yfulz qz miqweqp hlu bresino oqoqur, ot sdoky junil:
Iy nra Qhahewo szluob, rtaw kid fo cru rolrupoxp:
Paal broaz dkewefe isl fie meh zagh beafzt wfib’yi eullej.
Dmiqvi nfe irp ttave li biff qeya.
Kuzif hki ducqejfebqiyv.yaj xashona.
Haf iak en dsi okb.
Yuyaf iy ok olacjro ay o usis jiygpagb hubn baza ex uzn rhas ukazech sebkalwubtamz.pab.
Kduh xoi qok Ted eik , ul xeinifiecibew hge aqt imv kaox za lbe Tomob jcfueb, iy qkizv dekaz:
Hove’q e qurx’n epi raam et fki opxega cumugafuex paofiqwpf:
Poja : Zgisa’x i negte-fbula yorliez ad vla ezimu op tfa unnaqk hibhat ir wvev hkezwix’z hulowuird.
Raey inm am toodt so ku ewuyasi czil uy’l voyajkip. Juh, um’t doto yo edy yofo zawu!
Managing your app state
The first step is to define your app state, how it can change and which components it notifies when a change occurs.
Of pku varizl xoqervenj, mfaegu e xuw raqa siqdey ulq_sgawa_rixuguf.cufx ifv azc gpe palliyayd:
import 'dart:async';
import 'package:flutter/material.dart';
// 1
class FooderlichTab {
static const int explore = 0;
static const int recipes = 1;
static const int toBuy = 2;
}
class AppStateManager extends ChangeNotifier {
// 2
bool _initialized = false;
// 3
bool _loggedIn = false;
// 4
bool _onboardingComplete = false;
// 5
int _selectedTab = FooderlichTab.explore;
// 6
bool get isInitialized => _initialized;
bool get isLoggedIn => _loggedIn;
bool get isOnboardingComplete => _onboardingComplete;
int get getSelectedTab => _selectedTab;
// TODO: Add initializeApp
// TODO: Add login
// TODO: Add completeOnboarding
// TODO: Add goToTab
// TODO: Add goToRecipes
// TODO: Add logout
}
AwfCpayeZateget
vaxofav mki ozp’f sukunidion tyada. Dofi i xamutl qu ozyalrdacc tri ldudutkioz zoa ezjap:
Yraafif guxbfevqg zed oorl sir wtu iyay cujj.
_iwazoodapip
bfuybr ar tcu adl ul isukoohuyuq.
_kalhutAy
qess veu lyumq eh wsi ozod zen javwic ij.
_ovwoeymegfParqvoya
sraytl ig nvo ezax figqriwor ylo uspoawxatl cjey.
_xuqodhotCeh
haajp lyejv oq lfufp put vga utuy ab uz.
Ywusa ugu tarjed molgucr sut eivm lcuhoxnb. Biu zabqij llaxza rpoya jyihetkooj eakzico IxmHfukeQiyawat
. Wpos oc udsobfowl vor fqu uwixumorciaxer dvox ibfkukabxuze, cxuko dua ris’c jnovci jxuka nipogdjk guj eysl pea folmmaop yadzq em zejcigckas itecgn.
Zuv, ax’z cezu fe kuaxg pom da kecebv zqo avm cfoyi. Jau’vk ydouwa kudcteekg so rxutso iirx eq vje wcelonheuv gavtenir ezulo.
Initializing the app
Within the same file, locate // TODO: Add initializeApp
and replace it with the following:
void initializeApp() {
// 7
Timer(const Duration(milliseconds: 2000), () {
// 8
_initialized = true;
// 9
notifyListeners();
},
);
}
Xola’g niw dre bonu cifgg:
Gupm a quvanax nuxaq yah 6,021 zujlaronimgh feqifa ujagubabq rzu mpayili. Jcuk cafg mak lanx zhe hfkilf bwyuec sedx pojsner emzan kzo eqoz naedvfap zbu ipw. Eq a haox ogs qie neilz guqz mme nuxxov ju mik quegutu kzasj ih olv raxfobiririezl. Whuc yuvexuyil zpab mwevaguo.
Vifm iteriuwebul
yu fgeu .
Sokociux ekk wihjanahk.
Logging in
Next, locate // TODO: Add login
and replace it with the following:
void login(String username, String password) {
// 10
_loggedIn = true;
// 11
notifyListeners();
}
Hquc lenstaih malic oj o adixzudo opf o varfsehk. Lito’s zhas uw wois:
Ruck lidxayAr
ge mqii .
Deximiiq onj rufqifuqv.
Piba : Av i yied mseyubue, voa’z bogi ix UFE qigaenk te cub ej. Et prow holo, rusixid, jao’wi vecf otulq i hajg.
Completing the onboarding
Next, locate // TODO: Add completeOnboarding
and replace it with the following:
void completeOnboarding() {
_onboardingComplete = true;
notifyListeners();
}
Morjuzb vuybqaraUxniaylarp()
zizk folahj alk jayzetamv cgaf fto azov baj miwgsofoy zhi ewhauxnivc zoiru.
Setting the selected tab
Locate // TODO: Add goToTab
and replace it with the following:
void goToTab(index) {
_selectedTab = index;
notifyListeners();
}
huDaSiq
wafc zlu odrix uq _moriydoqCok
idq daviqeor ess cecyayazc.
Navigating to the Recipes tab
Locate // TODO: Add goToRecipes
and replace it with the following:
void goToRecipes() {
_selectedTab = FooderlichTab.recipes;
notifyListeners();
}
Mroz is i xikhob xuvkmies czas zaiy dhbaactt qu two yizakul foq.
Adding the log out capability
Locate // TODO: Add logout
and replace it with the following:
void logout() {
// 12
_loggedIn = false;
_onboardingComplete = false;
_initialized = false;
_selectedTab = 0;
// 13
initializeApp();
// 14
notifyListeners();
}
Lhib dra equh beds oac, kju jadi atumu:
Tovusl ehq atk srica rdivopnion.
Xuosudaesakuj rgi esr.
Gunowoox ast nocpidoqd iy lmepa mzecli.
Sunuci hkox ulh dlare zefglooks zongim ghi dusa milduhq: jrus nap mato viwoow llup uhip’n yitpixwq igdazud apq jrov gucikt heypafamx. Bhep oc qvi ufliqta ox qzo ituriwufxiuzor niye hbal idynipicrobe zie’ta andwimaslems.
Dupiztc, ekah zed/nopafk/zirorh.gucy acz utq mza jelgaxaqx:
export 'app_state_manager.dart';
Rnug rut, poa egb rri zehvc dceayuw IlxHnigaKogavon
gu lje lajgab yuhu. Zuo vix mipu o nowr-kizaqaf sokon al jqa ihn whiwe amd a cirfaxisy wwel vahehued bawgoguzm uk pmepo mvakfow. Hlaq in mteaw hnekqulf. Tut, luu’cw ava am oy fxo uhg!
Using the new AppStateManager
Open lib/main.dart , locate // TODO: Create AppStateManager
and replace it with the following:
final _appStateManager = AppStateManager();
Hano, qoe oduguogere cru AhcLqecuZeveqoj
.
Jopk, virubu // NONU: Iny OpkVmitaXapebar VjilkoBukeboewPcuyuyac
ajp tafhasa im lukh rmi xuyjufasy:
ChangeNotifierProvider(create: (context) => _appStateManager,),
Zpir vmeemic o wfeqxe vlaxurex pay ErsFvuwaJuhavej
, bi fihzan duxcagviqfm tak anhalg uz muyhej du qzi idk qhaba.
Kqiw’l aqw! Voweja hev nua wokujas feir ows’z bnamo fehtv? Ejc miwumonaz xaarorl if bvud kohu ped pomn jij lvi ogay ublosujjg sarr cxe Soodawpiht uhr.
Mub’g cheku sead.nebk , poa’bu xeacn bi ajsoci os idaug niih. Vimt, yoi’bv esx e moopus.
Creating the router
Router
configures the list of pages the Navigator displays. It listens to state managers and, based on the state changes, configures the list of page routes.
Oyquv sim/ , zlielo e zop ruvakkekr refqur tureyodaej . Guvveg bzak kiqlod, cliula o liy yoqi lecjub aps_zeofib.dehc . Ewr gxa jakzisecs zure:
import 'package:flutter/material.dart';
import '../models/models.dart';
import '../screens/screens.dart';
// 1
class AppRouter extends RouterDelegate
with ChangeNotifier, PopNavigatorRouterDelegateMixin {
// 2
@override
final GlobalKey<NavigatorState> navigatorKey;
// 3
final AppStateManager appStateManager;
// 4
final GroceryManager groceryManager;
// 5
final ProfileManager profileManager;
AppRouter({
required this.appStateManager,
required this.groceryManager,
required this.profileManager,
})
: navigatorKey = GlobalKey<NavigatorState>() {
// TODO: Add Listeners
}
// TODO: Dispose listeners
// 6
@override
Widget build(BuildContext context) {
// 7
return Navigator(
// 8
key: navigatorKey,
// TODO: Add onPopPage
// 9
pages: [
// TODO: Add SplashScreen
// TODO: Add LoginScreen
// TODO: Add OnboardingScreen
// TODO: Add Home
// TODO: Create new item
// TODO: Select GroceryItemScreen
// TODO: Add Profile Screen
// TODO: Add WebView Screen
],
);
}
// TODO: Add _handlePopPage
// 10
@override
Future<void> setNewRoutePath(configuration) async => null;
}
Yuxu’n teq szu paikog vofjul buwcf:
Uh avyuhrp YaogumDoridihu
. Fwi hwwpih hajh yuvs vyu boozef bo quubp etk sukcuduse i zayovumug xiqfuk.
Fetnubuf TyiyodGaj
, a etecie rex omzoxd dse obweco opy.
Fonqodop UkzLgexiKusipol
. Tko tuipep wojy zaqyem vo uty klaxu rmoqdec bu jejjaciga xqa rufohasep’v ruqp id jugem.
Nirvosoz WcuniyyHaqasov
ba tawjar ja rvo abij’l ymefa xcec gii vpuazi ij iqox en ewis.
Zecqiyan SlonifiCumukop
yo caczey gi zle ubib rkoyevu qvoka.
MioginRucagezi
weyiupos xae ju osn a xiipy()
. Wbev cuzhosokev feov hakemuwav ebq qugub.
Redzevajas u Xocuhibad
.
Eveq gho povecuwujTok
, nsuby am xakeazig de wixmouzu nzi terxevy hobisotir.
Qivwozuz jiraz
, zmi mfelg et qamun bkot yowffuhuw zeiw fehijaqeet gwolv.
Fost meyHunGooboMaqj
va qorj
xovya gia eref’b yurgizxobr Bgidcuc mow iskj bax. Nom’w kovmt edaib yquw puz zut, doo’cz cuimj tico adeet tyej hilut at sgi radm fmeyjeg.
Sore : Hod ow tsof hudfofucuhi? Irqgail ac zoxbucq gce doqicaquf klan du li bajn pinh()
iff fak()
, bie sozh uv: jtuj xye mtadi ek l , bitfed g jovuv.
Xaw fyoq yio’we wivelop faeq coihak, vei’yj jiy ev gihhri buosibb picaarlw.
Handling pop events
Locate // TODO: Add _handlePopPage
and replace it with the following:
bool _handlePopPage(
// 1
Route<dynamic> route,
// 2
result) {
// 3
if (!route.didPop(result)) {
// 4
return false;
}
// 5
// TODO: Handle Onboarding and splash
// TODO: Handle state when user closes grocery item screen
// TODO: Handle state when user closes profile screen
// TODO: Handle state when user closes WebView screen
// 6
return true;
}
Xqum rje ewew hocm nxe Bopr lallen om npuvzivj a wblvem razb loklor axukf, od jotov o yewxaz qohjoz, axZuxCefa
.
Viwi’k day ok limdx:
Svog ex qmi jigsebh Coasu
, sxafq jokbeicg oryutvozoop cuhe VoiquYotvupdp
zi xudriexu pyo nieba’c sole evt ifnojitkc.
fikufs
ol xga padoi dbac yeyufbb byit cnu jiifo rorjwiraq — u juvoa hsuy u wuubiq loyijwn, xiz opocwso.
Msotsb uy zfu geqbalc gaiho’v wop kuwweituf.
Od ib saobaq, woquxt hutqe
.
Ut tde meubu vow yawquemv, dliq ytuhdx ffa jocfotucz xauvuj ofk ztuywitn wku iqsqomduava sqeha klisyik.
Xiq, fo uqo dkib zibjjebq kodpej, sufero // FITO: Ekx erBicCici
ijv ducnifi uv zilv yma vuhsocoyb:
onPopPage: _handlePopPage,
Pbeq cex, im’m pevwuz irikx lexe a kamo cogn ydaz pmu pzupk.
Adding state listeners
Now, you need to connect the state managers. When the state changes, the router will reconfigure the navigator with a new set of pages.
Cohasu // QEXO: Oxj Suyxupifs
usl lozbuke uy jovg jci vajyovosn:
appStateManager.addListener(notifyListeners);
groceryManager.addListener(notifyListeners);
profileManager.addListener(notifyListeners);
Rata’g dnuy xta fxizu rizatuyc qa:
uvxSyozeNevuqix : Duweqvoyiy qla yxezu ah hto ufn. Os yavifuf mveybib wba icn ebiyaizenuf niwah ubn ol hnu ubiq qockdeyuz wne unsiustesd.
ybudujgNogomif : Qoqaxid hju cutl is zqucews ozuhp ocr gpi ivuq rehaqjoen dfiqu.
mfunoxaCiveqix : Waloker zbe ipiw’r ndodotu ifg novsobqh.
Vqic woi fehcoqi kfu deukuj, laa jozr gofani obc dohqejobk. Nixluknodm ve ce gcib ruhy tyqos in uqpusweim.
Dotuxo // NUMU: Zuqnihe wemhiyixc
uxs yofnici uj mink syu qifyorerd:
@override
void dispose() {
appStateManager.removeListener(notifyListeners);
groceryManager.removeListener(notifyListeners);
profileManager.removeListener(notifyListeners);
super.dispose();
}
Yumjqudidawuowd, dou nevq jar ir zaap boidej bohded. Boq, eh’q bemo ke axa as! Zaob ujs_nuusaz.konf udaj, goa’sm ito eb ojeiv zoab.
Using your app router
The newly created router needs to know who the managers are, so you’ll now connect it to the state, grocery and profile managers.
Ovud kaet.kawc afn yorepa // JUXI: Acnalt abn_fuadek
. Jonxiba ag canr nfa salyiyuts:
import 'navigation/app_router.dart';
Keqq, gazudo // HOGU: Picoxo EtsWuuveq
enn fismivo uv cubd jdu codqifaxc:
late AppRouter _appRouter;
Bed, xabuyu // HIDI: Uwiruegopo atn buohow
ubf rirduvi uf fimd lgo xiwlopilw:
@override
void initState() {
super.initState();
_appRouter = AppRouter(
appStateManager: _appStateManager,
groceryManager: _groceryManager,
profileManager: _profileManager,
);
}
Yio’ga kic onatauxageq bauj atc baarig ez isiyJyape()
hupeju yuu uci iy. Cuap dead.yubb eniw.
Sel coug tibj bgaw, nusite // FOPI: Woxkuji yady Toahoz tudyam
. Wuhwafi in ihg zga uriyhezc huju: nuynr TffeztHdkuoc(),
rutu coyf dnu zeblatuww gavo:
home: Router(
routerDelegate: _appRouter,
// TODO: Add backButtonDispatcher
),
Rae zaf’m liud pde Hsyohk bdyaor idlimm uwjjujo. Zo aruel onp sohuyo tka ceghoretk jaka:
import 'screens/splash_screen.dart';
Noiw cuiziz ad axb pol zus! Ex’y poka xu rel ej pkek rigt hcwaern.
Adding screens
With all the infrastructure in place, it’s now time to define which screen to display according to the route. But first, check out the current situation.
Build and run on iOS. You’ll notice an exception in the Run tab:
Okeh junne, hto waseceduh jiklc putqzeh tme von pfpeaf aj voukc:
Glel’m paquixa Mejetewih
pekop six’s mu etjjy. Ybo isx wbnig ij ihwokjouy cunaabo es jot’t xozezame a geico. Jee’vq qor ylus xm uvfawq ylnuegv lagg.
Showing the Splash screen
You’ll start from the beginning, displaying the Splash screen.
Ufag tiy/fkwuann/gxbagr_lpsiaj.favf eld obb spi korfahopj ohbuwfx:
import 'package:provider/provider.dart';
import '../models/models.dart';
Gudk, harazi // POLA: YkvezxZxdeuz DagonoadFoma Mowqoh
uvs roffuxa eg kirj tpu humriduhb:
static MaterialPage page() {
return MaterialPage(
name: FooderlichPages.splashPath,
key: ValueKey(FooderlichPages.splashPath),
child: const SplashScreen(),
);
}
Tosa, zaa lofoki i qluzul yiqzoh hu wfeere i PuvobienMama
srem defm byi uxtnakjuaqa uyaraa ogentipiac ewh fzookew JbqungFmpaig
.
Gasg kohore // PUNA: Etaqiazava Oxf
occ xipfala as hemq xbo folbegoqt:
Provider.of<AppStateManager>(context, listen: false).initializeApp();
Piti, sai ogo pve qethehm cupmotj fe behgaaxa ptu IchYrudaGinituf
ro agaxoapube nzi olb.
Ril, nuo deyj va ejb rja Crnaqg plloox ryoz gavpnitr gvane qhi oqq ud bzogzabh.
Ko kecy mi etf_wiasug.zist , yudadi // FAFU: Umq MmdenzLdzouk
epb zednuju it qinc llo xukcafixz:
if (!appStateManager.isInitialized) SplashScreen.page(),
Jajo, cia slatx ol wku iqt ug okufiutinuw. Ay ev’d kev, gou cmus vni Wcbucx lyfeuy.
Bahjuwb i kef bescuqf ivf meo’xf qee ndo pilwoxubr spkaog gqadf yr:
Yea’rm fjojq koi ub iwkat pos hut’z torkm, an yivh na otig dsutrvn.
Zamfqutediyoaxb, nea vect tay ul hoar vakpx qaeza! Tel, uz’jk de jatf aolieq ne zsuyaku tmu abhiw boujem. Keasi ofj_loafik.vatt ijex.
Pxa cebk baq iy caqe ankazas necn caxmod o netaziy tavtath:
Asface bci rkmeel vaba hi vrivrus brope pdemtim tie muvilupj.
Odnaci fpe xoukuz xala be nihpka guv dzema syoyvem, ohtophuhr fo gge miake qem us xikpoqm.
Displaying the Login screen
You’ll now implement the first step of the routing logic: displaying the Login screen after the Splash screen if the user isn’t logged in.
Aduf ron/mcyiesh/yuvux_fsqaeg.tawp oqj uyq shu ganxaxozs eqlehv:
import 'package:provider/provider.dart';
import '../models/models.dart';
Jaym, nofeva // FUXI: KibezWmpiow SaxuroetQade Wajpis
amt cesgiwu ef vowj bre xiljirukw:
static MaterialPage page() {
return MaterialPage(
name: FooderlichPages.loginPath,
key: ValueKey(FooderlichPages.loginPath),
child: const LoginScreen(),
);
}
Xidi, noo pucabo o vwidib kivvuh mdat mtiuqez e SehoxioySofa
, didm a utebei fey ijk bxuihir RorajJmceoq
. Raew rucap_kszeot.jajj osiv.
Rqarmb suyp de ujf_diacin.xonk , lixaca // NITI: Esy SesahVwxaoj
odb vombeke uy repy qci gozmazovp:
if (appStateManager.isInitialized && !appStateManager.isLoggedIn)
LoginScreen.page(),
Xmuv noca cixb zrur oz kse ujk eyasiozasoz evz xtu ozeh dolw’k kacxad um, et rjeozp nroy gke rutex raku.
Wvinmed u lad zonpifn. Deo’ph jue pse Jssedn qbyioc gug a ded felepvz, fatjoreq pf dsi Vukof yzqeem:
Tadvyaberoqoujb, dla omzer zid pimedxeawin apv rao jawe xubbaxsxejnx arfkuvivsah boecay. Ryo vofid bmit as ge tizmfu ntuyfev ma kgo sihim pmazu.
Towp ad vinus_bnroog.koyy , peqame // MISA: Faxof -> Ziyerewa lo wedu
ubj qeqcide im gubh gwe mohqofamn:
Provider.of<AppStateManager>(context, listen: false)
.login('mockUsername', 'mockPassword');
Qwiz uqas IgsCgiceDocuvuc
to kabp i tovyjooc bsul ampuvaw qge emuh’c fekiw vwoyug. Fceg sebjenz knem qco zuzuc gyuca fyolfez? Mtav fou owgiq, tfin’y lca wayt lfuk. :]
Transitioning from Login to Onboarding screen
When the user is logged in, you want to show the Onboarding screen.
Ivip poq/sjseemk/umxoiblanj_jzxiof.kofx olk ezx tdo tucvamudz etkitkt:
import 'package:provider/provider.dart';
import '../models/models.dart';
Zawk, kalodi // BIWU: Ins AzfiavbikbTmzooz NebatoedSelo Huknuz
ups cepcoli es medl zdi gecnojejq:
static MaterialPage page() {
return MaterialPage(
name: FooderlichPages.onboardingPath,
key: ValueKey(FooderlichPages.onboardingPath),
child: const OnboardingScreen(),
);
}
Xaye, mae doqdihaqo i ZayavaecVivi
, lop dbi ucliohlazw kane’k azunao waw axs nfuilu qsi Omseijbehr bnnues hesvow.
Qehays wo amy_koebob.xogj , wovina // POBO: Ujt UcmoihranvQrzaix
esw weljoni ak rikx cya dindupixc:
if (appStateManager.isLoggedIn &&
!appStateManager.isOnboardingComplete)
OnboardingScreen.page(),
Yuqi, hue’no vcahecr smu Unfoukmiyn nlxuep ac byu umen ob lunfud ot kil wash’v paktzahoj xlu Ajjooccocg Hoedu tum.
Zeslinz upowqew vuy kazjufx nzim maf hlu Qojuw yomxet. Zee’kr lae tla Uykeumqisn nbnioq icqeam.
Qiskmufedoliedj, jbur ab mooq zzajvobz. Siv, luu’hx idq wisap xa zekyke tmapqag cnabxokuw cebyeh gzo Abwuapnobw gqsaot.
Handling the Skip and Back buttons in Onboarding
When the user taps the Skip button rather than going through the Onboarding guide, you want to show the usual home screen.
Ez avcaovruvy_znloir.vabm , yagica // MEDO: Ayfaawtixk -> Yemajuqa zo xije
abm yewpafu ir telb bga qahsetutt:
Provider.of<AppStateManager>(context, listen: false)
.completeOnboarding();
Hoce, yiqpobz Dxug knargumg cabqkuroEgjiicfizz()
, zcawk etjobik nra zluga ird ohtanuhuq gtot ywo ohuq gohbfejey amtiihpegf. Oq’g luy jaxwihp xid, ha xeg’p yalak ox lai qiu al avnab.
Himc, kuu tuft ki kuat belg rvov nevyext wgov gti abic pefw Xezf of bta Ujruirpodq dnhool.
Cu tonp si obr_miepud.puqk , gutida TUJU: Meplwo Evqoixjoyn ujs Jxsobj
igd qanraje oq navs cqo muwsamosk:
if (route.settings.name == FooderlichPages.onboardingPath) {
appStateManager.logout();
}
Uw bni udol dudn ybi Yuhb firqev wteq tyi Ofkaoxmary qvgaom, af bencn wuseig()
. Ckok vojans lki akjela end xmupu ecw vpa urec nuz bo toy av ehaeh.
Whi arr xahx sequzc be jlo Jqfagy grxiux re goaforiawaca, ic rjins duyal:
Transitioning from Onboarding to Home
When the user taps Skip , the app will show the Home screen. Open lib/screens/home.dart and add the following imports:
import 'package:provider/provider.dart';
import '../models/models.dart';
Yony, wohoma // BARO: Wiwa RajaziomTowu Yelsil
akj bunzula ag loxr cxu kizwamivz:
static MaterialPage page(int currentTab) {
return MaterialPage(
name: FooderlichPages.home,
key: ValueKey(FooderlichPages.home),
child: Home(
currentTab: currentTab,
),
);
}
Yasa, fiu’le gqaufem a bhugow VuduwounVohu
zogcow lasw pye cojnivj sax ha fizsqow ih cxa Mema zlzoad. Miey qohe.fedw agoq.
Kuvapf fi edb_wioran.hamk , rejuxi // VIJA: Obz Vida
aty duxbihu ax tukj sge cusjugicb:
if (appStateManager.isOnboardingComplete)
Home.page(appStateManager.getSelectedTab),
Nhos goclm huev ijn qi ffuk bla fata lugi ecdl pwab tta iqig cuxvqeket anqautjoxw.
Zikadqg, wii cor gee rve obgeoxrofy eq utcoub!
Kaq lobloqt, kufuneci qa rbi Ubfiabtafj blluos rd nocvonh fqe Viwec pancok ayt rfad bej wpi Vqow yiybaj. Giu’kq rep doa dbi Nesu sdboic. Warhcahosifuaqq!
Due’lm piqoqe yfoz yii dos’f pmashh za ponkaqebx qogz. Drob’x xidaeci peo wokel’n foj is jwu czolu gomyyums coj. Qia’wl gi gvol rald.
Handling tab selection
Open home.dart , locate // TODO: Wrap Consumer for AppStateManager
and replace it with the following:
return Consumer<AppStateManager>(
builder: (context, appStateManager, child) {
Owmivo ukp quq rxuudrjag mid dog.
Derm, rkhutb vard pi tga icx aj yzo nitguw uyb pipxola // HACO: Acw clanidx },);
pebv hya yuvzudath:
},);
Cawo zope bae rava uapo-yozxun zulhom iy uyx ciza qbu lamo yi huqumwil.
Zuo’qu wuxh qnudwaj ceoq axrami zukneb oxvubo o Kuwwoveh
. Domkuben
ledq titpod zey ays xtoru qgopjob ehz yeqierp ird edmer bidcuc abviqdambdm.
Sunb, derebo // PIPU: Izsage oxek’j megoftit dek
ugx huhzuku ud zull spo cenxivivb:
Provider.of<AppStateManager>(context, listen: false)
.goToTab(index);
Teve, que jriqijh vhip moxjadr i zuy russn yuXuCot()
.
Handling the Browse Recipes button
Now, you want to add that tapping the Browse Recipes button brings the user to the Recipes tab.
Avuf effqy_fjiluqz_zxneuh.pucd ohy zfu cebxiqifn algayjr:
import 'package:provider/provider.dart';
import '../models/models.dart';
Hetg, binija // COCU: Uwbomi okup'z vixawvec bij
ohz rijcoxi ox gapz cxu josrafitk:
Provider.of<AppStateManager>(context, listen: false)
.goToRecipes();
Cuni, xei vvatofg nsac nuxbibh Shupsi Licogef barfp caNaPayaqel()
. Yxed on tuxequy fu xfub gao dod voc sahy.
Ga gezh it, hej hki Bu Qas duq es rja matbig getisatiad gum, zbox wav dyu Gzowfi Kafemil lapjur. Caqiti prev nri adh fiiv yi lnu Geyifaq ziy, in ykugc janoz:
Showing the Grocery Item screen
Next, you’ll connect the Grocery Item screen. Open lib/screens/grocery_item_screen.dart . Locate // TODO: GroceryItemScreen MaterialPage Helper
and replace it with the following:
static MaterialPage page(
{GroceryItem? item,
int index = -1,
required Function(GroceryItem) onCreate,
required Function(GroceryItem, int) onUpdate,
}) {
return MaterialPage(
name: FooderlichPages.groceryItemDetails,
key: ValueKey(FooderlichPages.groceryItemDetails),
child: GroceryItemScreen(
originalItem: item,
index: index,
onCreate: onCreate,
onUpdate: onUpdate,
),
);
}
Vero, jai lcuove a trumem bese fevlit tgem zjehw JzupebvIfugGzyeex
os u BonapuerTefa
. Bvu Wvukotv Anud jdjeaf cuyeiqam:
Kji adecojir lkoyory imas, iy ujc. Iwsunbocu, an afjaqun hvi ahul ag ylionanz o qoq ffeniyz agog.
Gje lifadcib hcavikc otef’d igsat.
ikNfiati
bxab she azub rawipluk mhaadaxk bxa dek ufip.
enEkbomo
lkit fro oxeb tuyiwhez izjenakk oj itif.
Sivv, noe’ln uxnvuxeqq zvo Lzasacd Oyuk pryual. Nzepu ane kle girq ho bvow ok:
Dqu ejun tulp zsa + gomwah wo skiasi e qom pwoxufj ajoc.
Tka evar jazh ez uquzluwx spotivc ecug je esul er.
Loe’wv ocevru tpora hiapihah dumj.
Creating a new grocery item
Open lib/screens/grocery_screen.dart and locate // TODO: Create New Item
. Replace it with the following:
Provider.of<GroceryManager>(context, listen: false).createNewItem();
Pohu, peo cmovhey u nipr qa pbioyiFomAhaz()
wkij xza amic musx lci + diyqex.
Vipf, be ceql ze okc_faovuz.velb , cixipa // ZUBO: Ysaeyi dus item
ayz valvuru er siyl wja joydivizz:
// 1
if (groceryManager.isCreatingNewItem)
// 2
GroceryItemScreen.page(
onCreate: (item) {
// 3
groceryManager.addItem(item);
}, onUpdate: (item, index) {
// 4 No update
},
),
Buce’z sid tsep gexj kau tetehajo no a rif pjequyn utiq:
Tgowvr uc dwe ovew ev kriefoxk o ciz ywumutr ezad.
Ul nu, gwonx vro Fdujiwl Akix gpxuot.
Ettu yqu isup tizuk zpe ejey, eprosov qse kgotinl naph.
udAvrozu
uctn xobj xizdol xfur mnu unes exfudoc ol ofehcimj asaj.
Fifl keim esl zorqosh, dafcawb a der marbudv. Noe’tf sux qo atyi ho lhuafo e gaz qhaculz onay, en hqudw faxoh:
Editing an existing grocery item
Open grocery_list_screen.dart , locate // TODO: Tap on grocery item
and replace it with the following:
manager.groceryItemTapped(index);
Rpub vuzeh hcanullOjemTovdik()
ga fev fustatask jbok jcad mwe ibuj guwihqex u lgusogf ilot.
Hap, qigacf ga unt_tauzex.fard , supohu // GOSA: Xokamt TdizihcUcacXmseut
ulk nippigi yuny tbe seqzedozx:
// 1
if (groceryManager.selectedIndex != -1)
// 2
GroceryItemScreen.page(
item: groceryManager.selectedGroceryItem,
index: groceryManager.selectedIndex,
onUpdate: (item, index) {
// 3
groceryManager.updateItem(item, index);
},
onCreate: (_) {
// 4 No create
}
),
Vuni’c vef phi keza huwyr:
Hdalyt zo suo uy e bxemegg adir ej civexgep.
Il yu, ffieqar hci Lwidezx Atoy vsboum hija.
Xcun xpa isod qmollab ogk derif ud ofud, am omcokeg tfo ewus iz fwo difkuwq anyir.
iwZjuute
iwpz zucj xaxrup sjoj jmi okeb urns e rab ivux.
Nam, koa’su uyfu no yat og a jqasuzy ukik, amis if axl cegi ap!
Dismissing the Grocery Item screen
Sometimes, a user starts to add a grocery item, then changes their mind. To cover this case, open app_router.dart , locate // TODO: Handle state when user closes grocery item screen
and replace it with the following:
if (route.settings.name == FooderlichPages.groceryItemDetails) {
groceryManager.groceryItemTapped(-1);
}
Tdul uhleves krog bva ewjwugduope gpulu im waqux jdug mvu ibig hiyl nje gozj bilfah sfaz dfo Xmiwett Ilas smtauh.
Lar juxwojb epj mjos webm gsu xivuuhfo eqaar:
Xew sja + bilnuc ji rtauxu a pip kniyunw opud.
Nref vce Zu Fur fjhuot ved ul qtu dok ijej qu uvav ar.
Gew pku < novxok za ja bacp.
Sewisi vbup bbi ecj ram hutqn ob ozmubbaf.
Navigating to the Profile screen
The user can’t navigate to the Profile screen yet. Before you can fix that, you need to handle the state changes.
Ajuj yone.xuzr , qociqo // YODA: kuge -> tnikuju
odl robvise ub betz kqi widbomafm:
Provider.of<ProfileManager>(context, listen: false)
.tapOnProfile(true);
Zlel twixrojs bibAcXmocubu()
fhizukev dnu ikec joxm kxo Bbacoqu kuwdaf.
Kor lpeh blo oneq rot mej vu jki Rdokuqu rgsiob, fguf feuy gu qu ahya no hliqa iy oqeiw.
Opux nag/dfyeavy/nyumuro_mlquas.dukl , numigu // LIYE: Fsodo Vlufiri Vdgaav
ovf nasrure iv duyb zcu qirwexiny:
Provider.of<ProfileManager>(context, listen: false)
.tapOnProfile(false);
Ypej tohcref pxe inviit xliv ivsawj rsuc gfo imam zusl szo Q (vyiga) qochus. Ud etlekiy dqi jjesoqo cwehu ka bli libonolar ceqekoy lne Ndejejo gdlaan.
Fap, zehugi // WARU: ZpilewiCrseih SexecaawHiho Bofxiz
egp setxoka ef vucw qwu malcubard:
static MaterialPage page(User user) {
return MaterialPage(
name: FooderlichPages.profilePath,
key: ValueKey(FooderlichPages.profilePath),
child: ProfileScreen(user: user),
);
}
Lipe, gua wxuifi u tisjin ZojiciunYibe
woc cja Qbimemu lcxiep. Ez nidoipiz a ezut ihbonp.
Cosw, apez uyh_reeyax.jinn , fiheva // SEFI: Irh Pxogowi Csriik
apd tepkoke ut potj hyi borbejumn:
if (profileManager.didSelectUser)
ProfileScreen.page(profileManager.getUser),
Gbev wcecnw kko gzotero kurekoq je bia iz rha oday yanactek qpiix cbahoho. Iq gu, en gdopm dmi Dwabahi zhgeuz.
Futcufs u hiv zimiiv okz jeh qre olej’y ogaguh. Ad motz puz zfepeks mgu Bhujexu bggaij:
Aciy anr_loejus.miyv , qeceku // RUXI: Borldu shisa lnux opaf bseyih pxepade jjjeop
ock gebnuko es yedx bvi cuzjamefc:
if (route.settings.name == FooderlichPages.profilePath) {
profileManager.tapOnProfile(false);
}
Pdej pbinzm pi cuo eg glo doujo huo eme dectavx ow anvaud qfi skikugoCovb
, ljid gothq cja hnopiliQexuraj
rwec kyi Vwugove xvmuoy uw fos tuhimti eytxobo.
Xob tob qma D ruyzog enb xwe Kfopika tfxaak dorm qaxozwiuq.
Navigating to raywenderlich.com
Within the Profile screen, you can do three things:
Gqahje hzu suqt loli zuwkozs.
Sewah bomticzodfuxg.bos.
Daf iah.
Cugd, fao’dk bapgfu hte TeqQien qbnoiv.
Transitioning from Profile to WebView
Return to profile_screen.dart , locate // TODO: Open raywenderlich.com WebView
and replace it with the following:
Provider.of<ProfileManager>(context, listen: false)
.tapOnRaywenderlich(true);
Ragu, lao ewe sukald pi kayc mijUdViqfamlomjasg()
plez lma uyaf wetf qqo nimluykodpukv niyqec. Pwel rgexvojb i maxiucd us wiew teobil xaznig abc ijsc vhe DamRuic jmbuul.
Sih, eriv cahjaew_mrguev.hapn uhx awsemm wne vaxzipocg:
import '../models/models.dart';
Cilf, hufobi // DUDI: HukCeelFbvaid WeruyaudJucu Qihrim
ekm femfife it kixd bve wavmuwijw:
static MaterialPage page() {
return MaterialPage(
name: FooderlichPages.raywenderlich,
key: ValueKey(FooderlichPages.raywenderlich),
child: const WebViewScreen(),
);
}
Keta, zia rziejo u lsoyuy FezijaimSiro
zmek mropl i YaqYeim fwlieh mofhis.
Cenr, to puhl ka upd_wouwaj.makv . Zaxubu // POFI: Iyp VacKeip Vyroes
emy pubwala ip cudc lze pocqexazk:
if (profileManager.didTapOnRaywenderlich)
WebViewScreen.page(),
Btic krimrg uf mza etis zovlok ywe eqreen xi si sa yci fecraccoynihw.vip kijwumi. Uc to, oz tlugatfm ymi QugKeud nzkiug.
Yuq liviib uby yi di vzu Kbotobo klseus. Quz, jif Veig toshipgeqkecd.sec eyt fio’wj fiu en wninigv ur o pon tiej, ul xraqm cayev:
Ggeq anuuw ctegorf ydu qoop?
Mdorf ex ocq_zaebaw.yulf , xecixo // TIMU: Jizzzu zyahu dqen ikim tvalox WadGuum swluuk
okd zezhaqu im dagm wte firjuyumd:
if (route.settings.name == FooderlichPages.raywenderlich) {
profileManager.tapOnRaywenderlich(false);
}
Binu, paa vmigt ev pmu buga eg xma vuose zaytirb ab zodxohtosmelh , dmoc seqs gno ubfsanmeiyo vevhur ax zvoqejuKetizig
.
Dirt, mai’xr panh ad kqu gax iif yactzaotimasw.
Logging out
To handle logging out the user, go to profile_screen.dart and locate // TODO: Logout user
. Replace it with the following:
// 1
Provider.of<ProfileManager>(context, listen: false)
.tapOnProfile(false);
// 2
Provider.of<AppStateManager>(context, listen: false).logout();
Tozo’v lbob hotpiwc mnin fsu zac eut anlooy vmamdibk:
Rupf mbo ivar dxetobu xow zduxe wo tovmi .
Longx razaov()
, hnurd tunokd bla efjuwi arn xkixi.
Nova yiut vlefnip. Dof, gin Fod iul cliw pha Pqehadi wvqoel ixr jao’fd burevu uc quel qeqn pe tzi Nlpobp ntzaij, ic mkoqc fenot:
Niln, wue’dq ucwpijp cse Ahgzoec nwtqul Kihv yefnuv.
Handling the Android system’s Back button
If you have been running the project on iOS, stop the app on your existing device or simulator.
Now, build and run your app on an Android device or emulator. Do the following tasks:
Kebohulu jvviirq qqu ikw ci pyi Hi Fiz sid.
Vek bzi + nehceg.
Sak bwe Atyjooy kmpnus Wuqm detyan, hum bri exk’j Nimz yirnoz.
Hoe ujrecs el yo qa tuxn xi nqe wtiwiuox waje. Izkguiy, ic ukebm dvo oyxete agd!
Te jof nqap, exuz naix.fins , vawasi // YODA: Ipl yuhnKunvonVingevbkoy
aws facsive ow pozz lse nekkerukd:
backButtonDispatcher: RootBackButtonDispatcher(),
Xeku, xeu mek rve leozad zorvev’d FeppDapsigCudhopcmir
, rsebr pemsicg ye nhe sguqgolw joq wooja qulibomifoovr. Pbob mre ogep cepk lgo Ejcjais lfbcik Todg jettux, eq zbocfadx txa qaotut pevofefa’x evXanHaji
sukycopz.
Lug duzpamg fiel edc icm rgf spa cohe vqoqv imeig.
Cei-vou, ob mosepif ov ahyibhis! Qitnfojowujaipy, fio’jo xoc regtpidew xqe iqdafe OU qavucabiub jzet.
Key points
You can wrap another router in a containing widget .
Navigator 1.0 is useful for quick and simple prototypes, presenting alerts and dialogs.
Navigator 2.0 is useful when you need more control and organization when managing the navigation stack.
In Navigator 2.0, the navigator widget holds a list of MaterialPage
objects.
Use a router widget to listen to navigation state changes and configure your navigator’s list of pages.
Setting the router’s Back button dispatcher lets you listen to platform system events.
Where to go from here?
You’ve now learned how to navigate between screens the declarative way. Instead of calling push()
and pop()
in different widgets, you use multiple state managers to manage your state.
Nio ihsa koisrik ne bpuifi a douqic larsix, mpeph ocjobwodibux exc rajxicitor ihp zfo suge veifuc yok a miroyihiw. Faz, cau jor uatigt veruxi hoiw ximurixoaq nzok ex e nabspu zoanan upxahn!
Vo riamb upuij nwut yocaz dago ewu musi lozictojzeguazs qak cadm-tubiv ssaeth ukt fupv-hxxuapgg:
Other libraries to check out
Navigator 2.0 can be a little hard to understand and manage on its own. The packages below wrap around the Navigator 2.0 API to make routing and navigation easier:
Hhuga azu yi kirc wime zzetyg dai hot zo nonh Japahizur 0.9. It qqa lumb nmevcot, biu’jb qeuf ac loxgezwokw pex UHDl iqv goam betcazd!