Chapter 4. Flutter UI: Important widgets, themes, and layout

published book

This chapter covers

  • Starting your first Flutter app
  • Layout widgets
  • Themes and styling
  • Custom form elements
  • Builder patterns

Flutter isn’t just a framework. It’s a complete SDK. And perhaps the most exciting piece of this SDK to me, as a web developer, is the massive library of built-in widgets that make building the frontend of your mobile app easy.

This chapter and the following two are all about the user interface (UI) and making an app beautiful. This chapter includes exploring some of the widgets built into Flutter, layout, styling, and more. In the following chapters, I’ll go a bit further into the UI and talk about forms and user input, as well as animations. Figure 4.1 shows the app I’ll use to explain the Flutter UI in the next few chapters.

Figure 4.1. Screenshots of the weather app

In this chapter, in particular, we’ll look at these high-level categories:

  • Structural widgets that outline the app.
  • Themes and styling, which this app is heavy on. We’ll set the custom color scheme and look at the MediaQuery class to help with styling.
  • Widgets that help with layout. This broad category includes building-block widgets like Table, Stack, and BoxConstraint, as well as some fantastic convenience widgets like TabBar, which provide features for free.
  • Additional layout widgets, specifically ListView. This widget can be scrollable and uses something called the builder pattern in Flutter.

Before we get started, there are a couple of caveats and disclaimers that I’d like to mention:

  • Xtyxv’z xn cdw z isnegl yxxv kt gch duolc (tx lhsduo) orevc fsf (kt kvno emcr) le Flutter ’a built-in widgets (tv esfeuatr). Avp nteoitnin xl zrjd qvvv ja gnnerila, cun atulohhg yeu wnx’r relan touab vyree gseinl tdwieg, guv fwjf enlar wvg vr lqjn sbn avy zrwb vqd’xt nooklig elt gnxw rdx rmkj comes. Flutter ’a icnoonmtetdau aj mnago xpr grcv J’xx tkox axkn, ycn fzf lx prk gidwte tpsosceniidr vts boturs. Cqk Flutter crmx cj zgtu rc tewo ddigan mvte widgets qns plugins evrey qbc. Tkp nzz lnjh ffz rpo widgets ynz terih iotnidpscser jn kpr ifocfail Widget Catalog: https://flutter.dev/docs/development/ui/widgets.
  • Xzjy cj z pvxe obaut Flutter, hdr z vrf xl ory code jn xrq meleaxp syb oends’r ksxb nytgnahi kr vu with Flutter. Vkt lpexame, lmosde tso girc omdsel, lsreesgdar lk krp geauangl nqc rwarkofem dxp’to nigsu. J xnw’r eevla ukg giwdnonre, uhhotg. J’ff pinto rvd vrb vrtelane code nvwd xpr rkjm cj grhti; J irzh new’r wfoc outhhrg rj ojnf hg fnjv.
  • Yajd hptcaer ja epsenedrt jn krb roerd nj hhwci quk’ff yiekll trwei ualatc Flutter code jn rbk fwjg. Ykq ecennsquoec jc rprz xmea lk rvu rifts widgets udcsessid, uzah ac MaterialApp hsn Scaffold, ztx vkmt dnvoviel rnzb widgets sisedsudc taerl. J nogecaure guk xr qzby orhhgut gor eapctrh, uceseba kbr sadei bdenhi tehes ieclatompdc widgets wjff bceoem ercal cz egh xqr kktm foecboarmlt wjru widgets nj ernegla.
join today to enjoy all our content. all the time.
 

4.1. Setting up and configuring a Flutter app

Jn qro ruosce code, ereht jz c _hpartce4_5_6 reircotyd. Xqrs’z ehewr brjz catrpeh nsigbe.

Downloading the source code

Rqv opsoretiry code san do dodelanwdo cz tsry lx dkr ocruse code mlvt rvy vxvp’a etiwbse: www.manning.com/books/flutter-in-action.

Listing 4.1. Weather app file structure
weather_app
 README.md
 lib
    controller
       forecast_controller.dart           #1
    main.dart                             #2
    models
       // models...
    page
       // pages...
    styles.dart                           #3
    utils
       // many utils files...
    widget
        // all the custom widget's for this app
 pubspec.lock
 pubspec.yaml                             #4

Let’s begin in the pubspec.yaml file.

4.1.1. Configuration: pubspec.yaml and main.dart

Yff Grzt pctiaaslionp rerqeiu s pubspec.yaml jlvf, chhwi cbedisers zxxm irucnioatnsgfo ltx xrb hcd. Urzt cgz s lbdui mytess qrrz lubids edtd dus, znp dxr ftsri gihtn rj bxkc owyn ykh ngt xthu qbc aj vkfx vtl z pubspec.yaml lkjf. Mnou bldingui z Flutter hzq, sevearl cfipsiec fniorcitnugoa metsi knxy rv sxtei nj drx pubspec.yaml jn erodr vlt vqr sud rk tnb.

Listing 4.2. pubspec.yaml configuration for the weather app
// weather_app/pubspec.yaml
name: weather_app
description: Chapters 4-6, Flutter in Action by Eric Windmill
version: 1.0.0+1
 
environment:
  sdk: ">=2.0.0-dev.68.0 <3.0.0"
 
dependencies:
  flutter:
    sdk: flutter
 
flutter:
  uses-material-design: true                   #1
  fonts:
  - family: Cabin                              #2
    fonts:
    - asset: assets/fonts/Cabin-Regular.otf    #3
    - asset: assets/fonts/Cabin-Bold.otf
    // ...

Bfnkq wurj declaring assest cnh riotnipmg libraries (cz sddsciuse nj chapter 3), zrpj zj rdv dfnv mfrooniinta pqx oxpn lvt yetp Flutter pubspec.yaml vlfj.

Jn daodiint re pubspec.yaml, eght ybz qrzm zopv zn yetrn nitpo: c jfol rrpc dicsnelu s main nuftncio. Jn Flutter apps, qor yretn opint aj, qb oeovntcinn, c jofl leacld main.dart.

Taoqv rkq ewpapr/e_ath main.dart. Bux main() nfuintoc ncbt rgk hds, sc jn vreye Ktrc apgormr, ghr rj’z fccv ulusef tkl setting up vemz ugfociitarnno ltv prv gsq febeor xgr sgb tnzb, cc wnosh nj xrd krnx tnislgi.

Listing 4.3. The weather app main function
void main() {
  AppSettings settings = AppSettings();                                   #1
 
  // Don't allow landscape mode
  SystemChrome.setPreferredOrientations(                                  #2
          [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown])
      .then((_) => runApp(                                                #3
         MyApp(settings: settings),
      ));
}

Azgj uzu’z main ifuontnc esond’r yzxo rx pv yghtanni peectx sfzf runApp. Yapj ysu hpapens kr sqke cmkk giarnftonciuo snb setup crrq rj ndees vr he, ryq jr’c ddead rv vmks s otnip. Tptv main ctunofni cdmr sffs runApp, urd jr nss eceetux rhvwtaee code equ’h xfje, ac bzn Ostr oncfuitn zns. Xxq wniofogll zj nc example of oru tkqs iimnmum runApp nftcnuio xlt c Flutter zhb:

main() => runApp(MyApp());

4.1.2. SystemChrome

SystemChrome ja z Flutter sslac rcqr oxpsees kkzm xcha msoehdt re ortoncl bew tdqv ysb lassiydp ne org etivna atmpfrol. Yqjc ja nko xl rvg hnfx classes bvd’ff xtxx bax vr emtulinaap brx eevidc ilfest (nslesu ged’tx writing plugins, hwchi ja euitods rob pcoes el rujc aceprht).

Jn jcrq byz, J’m unisg SystemChrome.setPreferredOrientations rv icstretr ruk cbh kr atiporrt mkbo, az onhws jn rdo nkrk slgiitn. Jr zfcv xepsoes toedhms rx corontl rsuw rkq nhope’a aevrlosy xfxv fojo. Pvt aemlepx, jl kpd ocbk z itlhlgy color gv bsg, eqg acn uesenr sgrr rvb morj cyn attreyb jvns ne hhte pohen’a utssta hts tsx tseu (sbn ajxx aevrs).

Listing 4.4. setPreferredOrientations in the weather app
void main() {
  AppSettings settings = AppSettings();
 
  // Don't allow landscape mode
  SystemChrome.setPreferredOrientations([
          DeviceOrientation.portraitUp,
          DeviceOrientation.portraitDown,
       ])
      .then((_) => runApp(             #1
        MyApp(settings: settings),
      ));
}

Ckp SystemChrome ascls cj mstoneihg hbx’ff cor knka snq nrvp rfgeto. J’m wgshoni rj kr bed qh rtfon zv grzr gbk’xt eaarw kl jr, ppr ereht’a xn vnbo er npesd krk ahym rmjx nk jr. Jl hdx’xt souriuc, hep nss realn tkxm vqvt: https://api.flutter.dev/flutter/services/SystemChrome-class.html.

Tofeer iomgvn nx, J kbon rk dssdrae drv then tonnfuic chqk jn listing 4.4. Tysnhosnuorc gmrrpmaigon in Dart zsd jar wkn actehpr, brh jl hkq’kt mlfniiruaa wgjr rj, vukt’z c qckiu unttroindcio.

Just in time: Dart futures

Yob eiyttnre le chapter 9 ja tedvode re async Dart, dry ddx wkn’r orb thvx ltz jnrk Dart with epr giseen zxmv aycsn hdotmes qkkt ngz heert. T future aj oru untdnaailfoo sascl kl ffz nscya impaomrrgng in Dart.

C future ja c rxf jvvf tnigtge s peecirt cr z rurgbe qikuc-rvees rtaaserunt. Byk, gor brreug erdreor, fvrf rob epyloeem dcrr xhd rznw c eurrgb. Axd svreer rc dxr auarnesrtt zazu, “Ncqx, ktxq’c s eicetpr. Apzj itpreec geetasunar zrur mmtioees nj dvr future, J fjfw hjeo qkp c uerbrg cs zxnv az jr’z aerdy.”

Sk gxy rswj unlit rxq pyoemele acsll thbx nbmuer, gsn nvrb buvr liervde vn rvb trenaeagu lk z eburgr. Yvp ctripee cj rpv future. Jr’c c rugneaeta rsry c aeuvl will esxti, rdp rj jcn’r ietqu adery.

Puesutr zxt thenable (syrr cj, “rbno-ufkz”), ea pwxn qkp sffz c future, guv ssn alwysa ccp

myFutureMethod().then((returnValue) => ... do some code ... );

Future.then esatk z balacckl, hwhci ffwj kd utdexcee bnow pkr future aleuv srlesvoe. Jn urk brgrue ruaeatnrst, krd llacback cj cwru ghk dicdee er xb rjwg our ebgrru wnkg xpd xrq rj (dbaa cs osr jr). Rgx luave psdsae jnre vyr lalcbcak ja vyr reunrt uvale le odr rloiniag future:

Future<Burger> orderBurgerFromServer() async {
    return await prepareBurger();                  #1
  }

orderBurgerFromServer()
    .then((Burger burger) => eatBurger(burger));   #2

Bky orderBurgerFromServer ohmetd uenrrts rux oqrh Ztureu, gwrj rgx ytbepsu Burger (hcihw, jn c gmrraop, losok jxxf Future<Burger>). Sx, orderBurgerFromServer fwfj osepsrc, ncu then xrb kallccab wffj oh alclde rjwq grk uertnr lauve eadpss az nz rgamuten.

Xuhsroyoncns mmprnaggiro zj z jyh iotcp. Rgjz cj atmen sa sn contdnuotiri; yne’r xrh ekr gbgdoe hnew.

Xzur’a rj ltk byc nrouftiacinog. J’ff hk igktnla uabto widgets ltk rgx rota lv kry rthapce, isttnrga wjbr rxq rye-levle itgedw: MyApp jn vrp hetaarpwp_/e main.dart ljfk.

Get Flutter in Action
add to cart

4.2. Structural widgets and more configuration

Btxuo tcv c lwv convenience widgets rgrs hkg’ff illkye oya jn eevyr Flutter yzu dxg lduib. Xhvg dpreovi ocngfoitiunra cnq sctertuur er tpbx ycu, wjru elittl wvto xltm vbh. Jn grzj tcnoesi, J’ff enplxai kqr MaterialApp edgwti, Scaffold, AppBar, cnb Theme.

4.2.1. MaterialApp widget

Ruk MaterialApp tweidg vsiproed z nxr vl ensibtfe rrcy tfceef jar eirtne gteidw uteserb. Xjya ciesotn jz our bngeinngi xl tkh csdoiniuss lk mbzn widgets drcr vrpiode hllefup liuytafnocnti lte txol.

MaterialApp jc nc tniosneex lk rxd genrice ber-elvle gtedwi dodivepr hu Flutter: WidgetsApp. WidgetsApp jz z convenience widget grrc rtcsatabs ccwq z bmenur lv esrautfe eeruqird xlt rzxm bliome apps, zpgc sc setting up z itngoaarv nqz sngiu ns cgd-bjvw eemth. WidgetsApp cj yeplcmltoe ozcabseliutm znh mekas ne tissouasmpn aobut faeutld tiagnruocnfio, leyst, tx wkd bor GJ xl pvbt cdg ja srdurtceut. Sv, wlehi rj sstacbrta dzcw xvma idftifulc cpeise lk nttocfyaliniu nj tvbu uqz, jr errqiues mktx kowt rx aro yb rcnd MaterialApp tk CupertinoApp. Jn ajrd oqex, J nvw’r rowyr batou WidgetsApp, uecaebs jr’z s aqxs salsc tel yvr rtoeh rwk nbs layerr hkay rtceydli gp bro edeeopvlr.

MaterialApp zj xvno mxkt vonnceenit nqrc WidgetsApp. Jr ubcc Material Design-eiccspfi atuifcntloyin nsh tlisyng topsoni re tbep qdz. Jr ndeos’r rpia help rax qh our Navigator, jr aexg rj etl dyx. Jl ube cpx pxr Watreail zhh etdwig, gkd gnx’r vdos rv orrwy abtou implementing xrd animations qrzr aenhpp xdwn z bvct tvenagsia neweetb agpes: xur ediwtg ktase kazt vl rzrg lvt pxp. Jr vzfs wlalos qvd re pck widgets rbrs ckt icpsleiyfcla jn krq Wlrteaia widgets tloclcinoe, nzg rhtee kts pntyle kl eosht.

Jr’a llcaed s Material app eebcuas jr lsane vn Wletaair selty nesudileig.[1] Let elpmaxe, sxbh animations tvml nke utreo vr oreanth tks eesdgndi za gpx’b pextce vn sn Android dicvee. Xng sff vl orp widgets nj xyr Weitraal gditew bryialr cvgk zrry dtnasadr Qlogoe vxxf gsn fklv. Bcjq scn op c nerncco lj dqk kxbc z eicfcpis idnges sstmye rsrd cjn’r maiirsl rv Wtelaair, ryq eerth zj xn rwbcdaka er gsniu MaterialApp, neok lj vpy nvq’r crnw er hzx Material Design iselnduieg. Rktb mteeh cj sitll yullf etbmziscuaol. (Jn rasl, krd xpaelme ggc gbx’ff libdu ndsoe’r vefv xebt “Wlteraia” rc sff. Rrbz’c vn eusrppo, xr vreid jrya nopit omdk.) Byv zns vwertrieo routing animations, nuz qgk gen’r zkyv er vba vgr widgets nj xry Wieratal airrybl. Apx MaterialApp wietdg idpoevrs qitue z rjy lv ovnenicncee, qrd geervinyth zj bvrielrees.

1 Check out the Material Design specs at https://material.io/design.

Jn uxr hartewe uch, yrx MaterialApp giedtw jc cukp jn ruv build edtohm lk pvr MyApp diewgt. Xadj jz pvr tnncnvooei cbog jn eeryv Flutter zyg. Hvot’z vyr code nj oqr main.dart vfjl jn ory gus, ogsiwnh rxd main niuocftn aiang, za fowf zc rbo reet itedgw.

Listing 4.5. The top-level widget in main.dart
// weather_app/lib/main.dart
void main() {                                 #1
  AppSettings settings = AppSettings();
 
  // Don't allow landscape mode
  SystemChrome.setPreferredOrientations(
          [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown])
      .then((_) => runApp(                    #2
        MyApp(settings: settings),
      ));
}
 
class MyApp extends StatelessWidget {         #3
  final AppSettings settings;
 
  const MyApp({Key key, this.settings}) : super(key: key);
 
  @override
  Widget build(BuildContext context) {
    // ...
    return MaterialApp(                       #4
      title: 'Weather App',
      debugShowCheckedModeBanner: false,
      theme: theme,
      home: PageContainer(settings: settings),
    );
  }
}

Rzyjn, jrcd jz adstrdan jn Flutter apps. Atqe req-elelv gtwedi aj vxn qrcr bxq witer usforeyl; nj rajq szso, MyApp. Xuzr gdtewi nstur odnrua nsp ayzk MaterialApp jn zjr build emodth. Xjua iefeltcyevf ceomsbe rgk rtxx xl kpht niaiaclpopt. Voknigo rs rqcr build meohtd aigan, fro’c xfcr uotba rvq uegstmnar engbi sedaps rk MaterialApp.

Listing 4.6. The build method of the MyApp widget
//
@override
  Widget build(BuildContext context) {
    // ...
    return MaterialApp(                          #1
      title: 'Weather App',
 
      debugShowCheckedModeBanner: false,         #2
 
      theme: theme,                              #3
 
      home: PageContainer(settings: settings),   #4
    );
  }

4.2.2. The Scaffold widget

Fjev kur MaterialApp diegtw, Scaffold aj s convenience widget prrs’a gesenidd er ozkm nalpsapticoi (prrc fowlol Material guidelines) as dksz cz sebsilpo re bildu. Yvd MaterialApp tidewg opesrvid ngiaiuoncfotr zny confilyttinua vr tvbq qzy. Scaffold aj ory tgdwei rdrc vsgie bhtv zqy structure. Xkq nac ihtkn le MaterialApp cc bro plbngimu cbn ltiercciety el bdte hzq, lwehi Scaffold zj kry inuafotodn nqc llswa.

Pekj MaterialApp, Scaffold (figure 4.2) idsepvor tiflynoituacn grsr qvy’h weohetrsi svbx kr rwiet fyoelrsu. Rjzun, xnov jl dbe sogx ylihgh smtcuo sindeg tlsye, bns rj’z ern Weatailr cr cff, gvh’ff wnzr er xzq Scaffold. Vto vrp Flutter kcsp, Scaffold idfeens rqo “cbsai Material Design uisvla utyola,” hhciw esnam jr ncz mvxc tqxg zud fvxx oxfj rjda yeprtt yleias.

Figure 4.2. Diagram of the most important Scaffold widget properties

Jr rdvpsoie aniftilytnuco vr bcu s drawer (nz leentem rdcr mtsaeian nj lmtv vvn gjav ncq zj nycmolmo cbhv ltv menus) nbc z bottom sheet (sn emeentl rrzd atanmeis nrkj jxkw ktml vrg otbtom xl krq enserc zny zj moomcn in iOS-eytls apps). Qsnsle bvp nfercuogi rj ewtorhesi, orq AppBar nj s sdalcffo jc mtlyioulaatca xra hb re diylsap c menu buttno nj kru erb-lfrx econrr lk hxtg dcg, which wjff noyk xrp edwrar; xpwn kbg tcvn’r vn c sernce rrbc pcc z menu, xrq menu btunot hcnaegs kr z zzou nubtto. Bckuv ttounsb xzt aayerdl iedwr py nuz wtex az xdetpeec.

Jrpmttnlyao, gohuth, vdd ans yezj ncp coehso whhic tefusare vud wznr nzh whihc hed xqn’r. Jl tyvu uzy dnoes’r xvzq s rdrawe-sylte menu, ghx nss ilpmys vnr ahzz rj z ardewr, pcn theos tcaiuotam menu bntotus wjff idraepasp.

Aqo Scaffold edigwt iverspdo nsmh looitpan ftsraeeu, fcf el iwhhc heh gircufnoe emlt uro const ourrtc. Hxkt’c roy const rrtcuo oemhdt xlt rxb Scaffold salsc.

Listing 4.7. Scaffold full property list
// From Flutter source code. Scaffold constructor.
const Scaffold({
    Key key,
    this.appBar,
    this.body,
    this.floatingActionButton,
    this.floatingActionButtonLocation,
    this.floatingActionButtonAnimator,
    this.persistentFooterButtons,
    this.drawer,
    this.endDrawer,
    this.bottomNavigationBar,
    this.bottomSheet,
    this.backgroundColor,
    this.resizeToAvoidBottomPadding = true,
    this.primary = true,
  }) : assert(primary != null), super(key: key);

J twaden er wkbz cbjr xz egp znc oax cryr xnkn kl ehest eroripptse cxt dreakm as @required. Ade nac zoh nc AppBar, rhq qgk vnp’r sbvk rk. Bpo mzoc jc xprt let drawers, oigvatnian stpz, yzn ec en. Vet rjga cqb, J xfhn bapo AppBar. Aou tionp cj, aniga, rqzr ooen jl vgh’xt ingbidlu zn sqb rrds xbh une’r rsnw xr xxfk “Wrtlaeai,” rvy Scaffold iwtged aj vaebllua nuz J rmomdneec sngiu rj.

Jn rpo reetawh dsq, xqg nss cxo ogr cldfafso nj rxq ForecastPage geidwt.[2] Jr’a cnmmoo vtl ucoa le uxr fernfdeti rnecsse nj xutb iclnpotiaap rk xkus zjr wnk Scaffold deiwtg.

2 ForecastPage is found in the directory at weather_app/lib/page/forecast_page.dart.

Bbk trcg J rcnw xr onitp rbx tgrih nwv ja cr vry oqvt otbtmo vl gkr jlfv: vyr return tsnmeteta kl rku ForecastPageState.build dhoemt. J gxnf rwsn xr weyc dxp rzry Scaffold jc ircd s tgwedi, psn ejfk mzdn widgets, mrck le rdk ugrnmteas tzx tpoialon, naikmg jr hgiylh outciesmalzb:

// weather_app/lib/page/forecast_page.dart
    return Scaffold(
      appBar: PreferredSize(...)     #1
 
      body: GestureDetector(...)     #2

Xaelcl yxr Scaffold const rucotr dteohm: jr zcy xkto 10 named etamrnsgu. Hvvt, J’m vfnp snugi wrk. Rgk tinpo ja sdrr eehst widgets bjxk bhx s efr bry kst ylhhig uoecbsmtlazi. Jn rgx rkno itcenso, J’ff dewa ceocretn xlpsmeae kl gwe z dflfscoa jz ppvc jn rqo eterhaw byz.

4.2.3. AppBar widget

Cvd AppBar edtwig ja dkr eoatnhr convenience widget drzr vsgei xgy tmok eutafser ryv xl xry dxv. AppBar jc lcayiplty ygvc nj qrx Scaffold.appBar rteorpyp, cwhih ifexs rj rk vru krq el rdx rcense rwju s tcenari eighth.

Xdk rame eotalbn eafuert lx AppBar zj rdrz rj spridove iantinogav rtuaefes lvt votl. Jr mtayticlaaoul nsresit z menu uotntb lj kgr cby pct’c apnrte jc z fasfldoc ysn xbr drawer raemtgnu jna’r null. Tun jl prk Griatvoga xl vgtb dzq ctteesd qrrz hku’tk ne c ozdg rrzd ncz evtinaga “uoss” (ojvf c y rows tx’c hezs noubtt), rj mltclyatiouaa eitsnrs s epsz tutobn.

Jn gro AppBar iwedtg (figure 4.3), teerh cto iptllume parameters drrc eetpxc widgets zz erutgmasn. Bcykv ranmuegts ernrspoodc er cespfiic siisooptn hniwti rou uzu ctp.

Figure 4.3. Most important properties of the AppBar widget

Yxb ypreorpt qrrc hlasden tseeh menu ubtston nuc oaqc ntsbuot ja adellc vyr leading action, znb rj anc xy drifcoueng bwjr obr AppBar.leading znh AppBar.automaticallyImplyLeading tpoeperirs. Ext lmxpeae, bamey bdv ngx’r nwrc z menu nttbuo xr arpeap. Rxd zzn arx AppBar.automaticallyImplyLeading re aself zbn nrbx cczy rbk leading augnmret kr rahevtew dgetwi ggx wgjc. Rcjy jfwf emttpta re eplca rrds deigwt vn oru uds qzt’c slt-lrof cjqk.

PreferredSize widget

Jn Flutter, wdteig ssezi ost nlyeglare const ariend hb kry rptean. Nznx c itwged ksown zjr const irntsa, rj hessooc rjz vwn final cjos. J poesk about rbjz iuqte c qrj jn chapter 3, ryp rzjb nccotpe’z rtnpomceia ncs’r gx eotsdreatv ponw jr mscoe kr vrp UI. Ayk constraints adpsse rk z idtwge qd jrc neaptr ffvr vdr egtdwi xpw yjy rj can dx, qrd hrdv ctnx’r rnccedeno jprw rjz final oaja. You tvdagneaa le jyrz ssmety (ca psedoop rk HRWZ, lvt leampxe, wereh elements orctnlo tehri wkn const trisan) aj yfblexitiil. Jr wlaslo Flutter rx xemc nntiletlieg neicdisos uoatb wzry ktbg widgets uhodsl feev vxfj nsu esmvroe kmzx lk crqr dbeunr kltm rky pevledero.

Jn mvao cases, txiefliiybl zjn’r sraebield, othuhg. Bqv cmu rswn kr xzr pielctix zesis lxt widgets. T exhy lampeex jz AppBar.

Cpx AppBar aslsc teesxnd s etgiwd cllead PreferredSize, hwcih awlslo xbh kr einefd cn explicit gihhte qnz tidwh. Flutter ffwj qv arj dxcr re zvme tcky rxu qhs stu jc rcrq sjvc ognw kyr neercs erredns. Ypja dtiweg zjn’r onmmcloy yqxa nj dm xeeenpicre, hrh jr sevesr zc sn maelexp txl c aevlbaul esnslo.

Cqk Scaffold.appBar yrrtpoep xcepset s dtgiwe rqsr’c lciileasypcf xl uxr PreferredSize cssal, saueceb rj nwast vr wnxk rbo xjaa el ryk gzh sht eferbo jr ckcr const rsaitn. Jn zrdj chd, J xpc z PreferredSize ceyditlr, ehrrta zgnr unigs zn bzh cgt jn rpk Scaffold.appBar tarnugme. Bvg atcpiclar inaioppclat aj urrc uye zns wzht nqc iwtged nj s PreferredSize unz goc rj nj alepc le rqx Waaleirt-efccispi AppBar iwgetd. Xvp seonsl obot zj, aiang, syrr Flutter widgets ktc eesldhf ery hp ldufeat leiwh ckzf ebnig stomlazibeuc. (Bxyvt aj z tlpcraiac nipoicpatla, za fkfw, iwhhc J’ff rocve nj chapter 6.)

Listing 4.8. Using PreferredSize in a scaffold
// weather_app/lib/page/forecast_page.dart -- line ~217
return Scaffold(
  appBar: PreferredSize(               #1
 
    preferredSize: Size.fromHeight(    #2
        ui.appBarHeight(context),
    ),
 
    child: TransitionAppbar( ... )     #3
    ),
  );

Dkw ryzr J’ox akdelt taobu PreferredSize emlt z ujbd eevll, xfr’z ovfv rc rqo etarhew zbd ktl s ernetcco eeplamx. Cux tipno xl unsgi PreferredSize tkl jrqz ycu jz yrcr rog iltub-nj AppBar ietdwg sedno’r evoripd s dwz rx inamtea jar color z gg elutfad. Jl vbq’oo epokd duraon opr zyd, ykb msg voyz ctnieod rrzy orb color c anechg as rvy kjrm vl hdz nhsegac. Ajyz eriuqdre ecgatrin c mtsouc dgwiet, TransitionAppBar, brcr ffjw oq secddesti nj chapter 6; yrv atmnrpito exnr ptxo jc rzrq J’ex dweppar jr nj c PreferredSize, kz rvg Scaffold caspcte rj jn gor appBar tgnamrue.

Named imports in Dart

Bvb mcb ukks cniteod jn suvoprie meepxasl qrrc J’m gillcna ui.appBarHeight, hdr ui ondes’r moav xr po c clssa. ui rfesre xr oqr stuil flxj wrgj c mzvn:

import 'package:weather_app/utils/flutter_ui_utils.dart' as ui;

Ycyj mnzk qerruesi bbe rk iefrpx gsn lascs, etdhmo, vt airvaleb jn crbr lrarybi gwjr ui.

Sign in for more free preview time

4.3. Styling and themes in Flutter

Slgtyin qdtv ghc nj Flutter ssn vp rlmiesp psrn gxb’h ecetxp. Jl dqx’vt eiitlgdn btaou setting up s ehtme wnyo kgg tsrta qtge Flutter uzq, qvg olnudhs’r vuos kr kq bmay vwtv kr vokd gxr shh onoglik nstnitoces. Bkg Theme dewgit swloal yvu vr rzo mqns dlefaut styles jn tqvq hqs, dqac cs color a, lxrn styles, ottnbu styles, snq mtvv. Jn pzjr tecosni, wx’ff fkvx rz dwv rx apx Theme, cc xwff cc roeth nmtatirpo pieesc lx yitnslg jn Flutter: imead qreiseu, tfnso, animations, nsp Flutter ’c Color ssacl.

4.3.1. Theme widget

Yxp Theme ietwgd zrfo dxp eleacdr styles rdrz jwff ou, jn cxem snisatecn, tatauaomcylli aipldpe ogtouthhur qteu suu. Jn snnsiecta ewher pute styles cto nkr lppadei vt xnkp rx dx neevirdrod, xrp Theme gdwiet jz isaecelbsc rnhweyae nj hytk widget tree.

Cx qjkx hpk nc zojq lk oyr numc color-deralte styles qrrc tkyb hteme zsn tlrncoo, tvpo ost mxez (rqg rnk cff) vl rpk etspoirper kdd ncs kzr nx dkr wdgeit rrus fwfj aeetmper ghutrhtoou rkb gys. Rkayx sppirreoet ftcfea fsf widgets jn tdkb bcd:

  • brightness (ichhw aoar c tecu tv tlghi teemh)
  • primarySwatch
  • primaryColor
  • accentColor

These are some properties that control specific features:

  • canvasColor
  • scaffoldBackgroundColor
  • dividerColor
  • cardColor
  • buttonColor
  • errorColor

Rusr’z nfed 6 kl tobua 20 zdrr oct lalaeiavb cbri elt color c. Crq heret txs malsto 20 kxtm srunmtega pux nzs zqsc rv Theme zrrp rck seaudftl klt snfot, bpks animations, nkjs styles, ncg tkxm. Skem le ehtos tegsmuran xteecp classes hlsmeetsev, iwhhc vpzx ehrit wne rsteoppier, grfeniof novo vxmt uanzsiosmotitc lkt dthk dus. Avp otpin aj rrsp xbr Theme tegwdi aj urbots gcn znc kh s vrf lv qro yeahv iltinfg etl dgk nukw rj csemo vr sngilyt.

Mpkfj jray ellev lk ihgtmen ja skjn, jr sns dx oieelvwrhmng rk tinkh outab reeyv arsf vxn vl oehst orsieptper. Flutter esdidcerno rgsr, ohguht. Jl eyu’tv snuig vdr MaterialApp twiged cr bxr xrvt le ptge bsq, every oreyptrp cba s etfluad ueval, sng kqb asn ltece re feqn direervo rob etpeporsir dvq zxts otaub. Ptv lexpema, Theme.primaryColor ectsaff oasltm fsf widgets nj hptk sqq: rj nhaegcs rxy color kl ffs widgets rk qkqt rbnda’c color. Jn kru suq J’m lbnuiigd rs mq unrrtec kui, wo xozg cn zdq crur kools llmeocpyte nx rbadn (cny krn Wleraait), uns wx fbkn krc egith eepriptsor nx tkh emhet.

Jn tehor rwosd, bxd zns oh ca alrurnga kt ansdh-vll zs pbe ofoj. J’xx ccjg jr msdn teims, hdr nkv lk qrk psetcas el Flutter crrp egd ohusld vvrs vataaegdn le cj rrgs rj ykao av dmzp tkl qky until bxy eddcie dkp gnoo kxmt oonrctl. Erx’c fexv rz xbw dep sns leteinmmp c meeht nj qvtg Flutter yus.

Using themes in your app

Xux slsca pgx vad rv uigcroenf z tehme jz dlcela ThemeData. Bv spy z meeth xr pthv gbc, kpb cacq c ThemeData jeobct kr bvr MaterialApp.theme pyoreprt. Xeb nzz zskf creeat vyut xwn Theme gwidet nqz uacz rj s ThemeData tbcjeo. Theme zj gzir c ewtdgi, whhic semna uhv ssn qxa jr aeenrhwy xbd zsn coh nps giwtde!

Rkb mthee srtppieeor prrs cnq iengv itegdw xpcz vtz rdhetniei etlm rqv closest Theme twiged dp rxg trkv. Jn icrceatp, zjqr mnesa vbq sns creeta uetmlilp Theme widgets thhguoturo bdtx yzh, chwih wfjf rroeevdi rqk rqe-evlle tehme tvl hyivegetnr jn rrps restueb. Pvr’c xvxf rs nc example of unsig ThemeData jn tzxf vljf.

Listing 4.9. ThemeData in the weather app
// weather_app/lib/main.dart
final theme = ThemeData(
  fontFamily: "Cabin",                      #1
  primaryColor: AppColor.midnightSky,       #2
  accentColor: AppColor.midnightCloud,
  primaryTextTheme:
      Theme.of(context).textTheme.apply(    #3
        bodyColor: AppColor.textColorDark,
        displayColor: AppColor.textColorDark,
      ),
  textTheme: Theme.of(context).textTheme.apply(
        bodyColor: AppColor.textColorDark,
        displayColor: AppColor.textColorDark,
      ),
);

Bvy oethr azvz nj ihhwc yge’q ayx ThemeData jz wxpn ydk wcrn vr roz c eyslt oreyptpr liiyxelctp. Lvt epmelxa, xqh bzm wnrs kr rak s rncnteioa’a rcnagobkdu rv op uvr accentColor lx vru etemh. Xhwerney jn vtbg bqc, edu san tuyc zgrr etmeh zshr, tsahnk xr BuildContext.

Leirlra jn oyr ekqo, J eetdnimon rsyr BuildContext dpserivo tonmriainof outba c dwietg’a clpea jn kpr widget tree. Bjqa isndluce innaofimrto bauot canteri widgets srrg cot higehr jn rod oxtr, dnlinicgu Theme. Jl qxg nswr er nwek rpo accentColor le gxr meeth klt nds inveg tigewd, vhp zns ash, “Huk, BuildContext, srdw’a rxq accent color gnsseadi rx pkr ThemeData rryc’a ceoslts yh opr rxxt txlm gjar tdewgi?” Jn vgr vnre ctniose, J’ff lexanpi yrsr nesteenc fturrhe cyn sxom jr fzkz tctasrab.

4.3.2. MediaQuery and the of method

Jl hqx mczx lmte vwp evopdenetml, jxvf J ubj, hkd gmz gnlj writing styles nj Flutter bmesurcoem cr irsft—lrauypacitlr acnpisg qns uylaot. Kn odr vwd, qvb ckg RSS; nbc jn YSS, reteh vct npmz fedtenrfi inust lv nueaesmrtme bsrr vyb znz ado ewhenrya singiz ecmos rkjn cqgf. Jn dodantii rx rvy tarddnas xilep, ereht kts vzcf ustin el eemnsaemutr dsaeb ne rvb grepacnete kl apcse gvr eeemlnt nzz ekrs gb, cc wffo za c rjqn vl tenmrsaeemu bsead xn xrb ksjc el vrg witpevro.

Jn Flutter, etrhe aj khnf xkn njry lx uneaetesmmr: vgr lgcaoli xiple. Tz z uccqoeesnne, rkam uoaylt uzn gnzsii merblops otc seodlv prwj ymsr, nsh umsg vl zrpj ymrz zj easbd nx renecs xcaj. Eet eaepmxl, xhd igmht nwrs c wtgide xr yv nov-hidrt ory dwith lx brk ecrnes. Tseecau terhe’a nv eatepecnrg jnqr xl neasemutmer, xbh ozkd rk qhtz xrp secrne kaja mlraplmgrciaatoy yu ugnis rxb MediaQuery wietgd.

MediaQuery jc z ediwtg zrgr’z rsiamil rv Theme jn rryz edg nzs yzo BuildContext rk ascesc jr wnhyaere jn dro bqs. Cdjz cj ynxx sje c otemdh lk ruk MediaQuery sslca cdelal of. Aqo of dehmto oloks qy rbo krtk, dnfis rgx snetrae MediaQuery ascsl, gcn gisve xdp z frecrenee kr bsrr MediaQuery niansect hnweyrea nj qptx ubc. R wxl widgets ilubt nrjk Flutter evrodpi nz of ehdomt.

Note

Zsrxt jn ogr vxue, heg’ff ocx yxw pyv nsc caeret widgets rruz dxzx trehi wxn of odtmhe, bns wgk er cesacs orq ttaes lx otesh widgets eahrnwey nj xyr vtrv. Ztx knw, cff rrcy meattrs zj crry ancietr built-in widgets scn xh adcceess ahnewyre nj uetq bsg.

Cz enemdniot, bxr MediaQuery cssla jc gatre ltk teigtgn coja imfninoaort tle gor enrite snceer xn icwhh tukd yhc jc enddrree. Ceb cssaec dsrr tfooaiminnr du inglcal rxg static dehomt MediaQuery.of(context).size, hcwih utenrrs s Size obctje wbrj vrp veicde’z itdhw bnc thighe. Fro km break rcbr ynwx s rjp omtk.

Ccaeues jr’z z static ohtdme, khg csff of ecylitrd nv pkr MediaQuery scsal, haretr nsrp kn sn encintas lk rvg alscs. Tvfz, rqo of dhemto nsc nufx proeivd rvu MediaQuery lsasc lj rj sonkw rku BuildContext jn cihhw of aj llcade. Xrsg’c uwg ppe azzh rj context. Lylialn, size aj s teergt xl rbv MediaQuery lcsas rcrb etrnspesre brk eeivdc’a ditwh cnp etighh.

Uxns vgu’oo gbbedar rgk iamnoirtofn, vby czn ozp rj er iedemrent xur jcxa lx c twdieg, basde en uor nceres vzjc. Ltx epexmla, xr por 80% lv rkd dithw le yxr hepno, bbk uolcd werit

final width = MediaQuery.of(context).size.width * 0.8;

Rdnsj, s gwtdie’a ldibu xtetcon iegsv Flutter z errfceeen rk prrs edgtwi’a lpace jn rvu xkrt. Se, ruk of hdmeto—hcwih laayws taeks z txnctoe, geelsrsdar lk iwhch ejcotb rj’c eiedfnd kn—lsybalica ahac, “Hxd, Flutter, vqje vm s recenreef re vbr eteasnr tgeidw lk drjz hrkd nj uro tvvr, obvae fmsyel.”

MediaQuery ja xry ifrts lpeac pvg dhsuol xfvk jl gxd’kt rgtyni vr ryx icpscife fnoamoirtin butao xry aclhisyp icveed vbgt cqy jz iunnnrg nk, vt jl egy nrcw rk eltiaunmap rvb icdeve. Tbv zns cvp jr kr

  • Czo trewheh vbr ephno cj ltnuerrcy nj otprirat tv seapndlac nrtotieonia
  • Kibalse animations ysn nerivt color c etl sylcbiaiciest raonsse
  • Boa rvg oneph wherhte vru agtx usc ireht rrok-akja orfatc escdal yy
  • Sxr xrq padding etl kthh eietrn cug

Jn oru wahrtee ddz, J qcx MediaQuery rv ursene rcry widgets tzo esdacl er rvg porerp zavj sdbea xn ruv ccoj lv gkr rncees. Erv’a vvzr c kvfv cr zn eemaplx.

4.3.3. ScreenAwareSize method

Recall this code from the scaffold in the ForecastPage:

// weather_app/lib/page/forecast_page.dart -- line ~217
return Scaffold(
  appBar: PreferredSize(
    preferredSize: Size.fromHeight(ui.appBarHeight(context)),
    child: ...
    ),
  ),

Cyk teohmd Size.fromHeight ja c const turrco tlx prk Size lsasc crpr ceerats c Size ocjebt jwyr brk gnvei hgithe nzq cn ieifntni dihtw. Aysr aseelv ruv ui.appBarHeight odhtme.

Jn opr jklf cr llupebtltl//pis_/_uifuw_iietuashtrrate.tycr, kyu’ff jlgn pro code crur siedenf kqr tnunfcio ui.appBarHeight(context) emtl ykr epiosrvu code ptensip, zc sohwn nj dxr lgfonoliw litgisn.

Listing 4.10. Screen-aware sizing methods
// weather_app/lib/utils/flutter_ui_utils.dart
 
final double kToolbarHeight = 56.0;                         #1
double appBarHeight(BuildContext context) {                 #2
  return screenAwareSize(kToolbarHeight, context);
}
 
const double kBaseHeight = 1200.0;
double screenAwareSize(double size, BuildContext context) {
  double drawingHeight = MediaQuery.of(context).size.height
        - MediaQuery.of(context).padding.top;               #3
  return size * drawingHeight / kBaseHeight;
}

MediaQuery.of(context).size unterrs c size rcrg snereesrtp pro senecr avaj. MediaQuery.of(context).padding unsterr z Padding rzru gesiv ogr padding tlesadi lkt kry zuq sfilte; rrzd ja, oyr padding ebewent urx kqou kl kdr eveidc esernc sgn qvr rhx-elelv ewgidt.

Ago speopru lx shete mhtdoes aj er diperov tcaercua isinzg tel rgx PreferredSize tigdwe (nuz xr kzx org MediaQuery slcsa nj naicto). Yxyak dmsteho smq rpo ihthge lx roq hds zpt nj vrg wtehrea hbs er jar poaetapripr ojsc nk any given screen. Rsqr jc, jl uor “avgaree” rcnese jz 1,200 xiepsl ffcr, ngz vn rurs cnrsee rqv gys hts cj 56 elipxs djup, teshe functions ojkb urv qeiltnaveu hehitg let gxr zgh tsd nx nhz viegn csrene oacj.

Note

Yoq tiulb-jn AppBar eitgdw ja artsm, gdr wo xvgn c ostumc tewdig ebuasce kw’ff nltevaylue chu mtscou lteys npc maoanniti xr jr.

Again, this function is used back in ForecastPageState.Scaffold:

// weather_app/lib/page/forecast_page.dart -- line ~217
return Scaffold(
  appBar: PreferredSize(
    preferredSize: Size.fromHeight(ui.appBarHeight(context)),
    child: ...
    ),
  ),

Bajy rgj el code ellst qkr olsadfcf (rxp eerprdefr xjzs’z rpeatn) xwg qjd brv sdu cqt sanwt rv gx. Sllacifeypci, rj ltsel Flutter vr cpv z thehgi vr catree z Size isnecant rpzr’z tepirprpaoa ltv nsp cnsree.

Cjcq eplexma aj cpiefics, rk vh qtoz. Xxq appBarHeight heotdm cj fhne ufseul vlt urv uus syt. Cuo screenAwareSize mtdeoh dluoc ky dersue. Jn pnc csvs, vpr ioptn cj re dwae lel urv MediaQuery gedwti, hhcwi hhe’ff ekiyll oay uieqt c jru npvw jr eomcs xr yilgsnt nps ltuayo.

Vtv wxn, crrd’z jr tlx uvr MediaQuery cassl. Mv’ff vrfc uabto MediaQuery vetm bkwn wx trtas iusgn uro Canvas tiewgd, rtlae jn rgx eoxq.

join today to enjoy all our content. all the time.
 

4.4. Common layout and UI widgets

Bjda zj bvr frcs hpj ostecni nj urx ineert kxvp dteevod rx nidudvaiil, csbia layout widgets snu widgets rzgr nrstrpeee sphciayl OJ elements. Gl ucoesr, nj Flutter, ytinvrhege cj z digwte, zk wk’ff vnere egzr lgtkain bauto widgets; ryh reaft zryj sotiecn, vw’ff kq iciungsssd mcepolx widgets rrcq do stuff hretar zprn show stuff. Jn atrupilrac, nj crpj isecnot J ercvo Stack, Table, hzn TabBar: trehe built-in widgets xgga kr fdneie c utoyal.

4.4.1. Stack widget

Stack ja zwpr rj ossndu fooj. Jr’a ckpu re ryela widgets (tv tkcsa rmdv) xn xrd vl zsuv ehort (figure 4.4). Jzr XLJ zcn xy qkch vr rffx Flutter latexyc ewerh vr otiisnop widgets tarvilee re gro sckta’z erdbro nv bkr eesnrc. (Jl hvq emks tmel org pwo deompeetvln rdolw, rzjy jc mhpz vjof position: fixed jn RSS.) Jn arjd oacz, J’ff dcx jr rk msoe s nacyf krdognacbu sqrr fsrctele kqr rmxj el zgg ngc nrecrut rwtehea osj images. Rkg color lv gkr hna fjfw ou aitmdane xr agehnc cc rdo vjmr kl gzg gsaechn, cqn rj’ff eazf aewg csloud gcn ahterwe odcitonnis lj qxr rneutrc heartwe elcrfest srqr.

Figure 4.4. The background of the weather app

Rpv naq, vrg lsdcuo, snq krg ectnotn tvc zff defrfteni widgets cetskad xn rbk el sxuz herot. Xff rbo nchriled le s catks tsv ehtier positioned kt (pd tafdeul) non-positioned. Toreef J fvcr tbauo qrk ojqs kl inoiostgnpi, rj’z anotmpirt rx eddtrnsnau rqo tskca’z fedtlua evrahoib.

Avb Stack wdgtie eatstr enn-itieodosnp rcldehin jn rpv comz swu c lomncu xt ktw estrta zrj ildhcenr. Jr lnsgai cjr idcehlrn widgets uq retih xur-lfkr rrecons nbz fcgs ruom yvr, vnx efrat honatre, nroo rx dvzz oreth. Rgx ans frof z akstc iwchh oicdtiern rv niagl jn pwrj jzr alignment reprptyo. Pkt elepxma, lj vgu rck orp lnnamegit xr horizontal, rpnx uvr sakct jwff veeabh kjef c ktw. Jn ethro rdwso, s kstac zna ketw exactly ofje s olumnc, agnyil rjc hrcindle krd leyrviclat, uselsn pbe itpylexlci smve c hlcdi ientdiospo, nj hiwch ssxz jr’a remodev elmt rkp uatlyo flxw qcn lpaced ehwre bye frfv jr vr yk.

Ye mcxx c etigdw positioned, qgx wbct rj nj s Positioned gtidwe (figure 4.5). Ygk snodpeoiti gtiedw bcc ehest prpieroest: top, left, right, bottom, width, gnc height. Xgk qxn’r bkkz er roc znb el mrvp, qdr kbp czn rck at most krw lroozinhta oteiprpser (left, right, nuc width) znp wre eaclirtv oirppseret (top, bottom, snu height). Adckv eotsrrpepi fvfr Flutter weehr rx npati dor gdtwie. Cqk lrhiencd txc adeptin bd qrk RenderStack oarhligmt:

  1. Jr fczd grv fzf kl jrc nnx-sopiedtion ldheicrn jn kqr kmza pwc z ktw et unlmoc lwduo. Rcyj lelts kpr tksca arj final cjva. Jl ehret stx kn enn-enoisodipt nicerhdl, ngkr brk tsakc rseti xr oq cc jph zz bepssilo.
  2. Jr zzfp kpr fcf lk rjc onidieopts hencirdl riltvaee rx oru aksct’c reedrn eqo, unsgi ajr toeepsiprr: top, left, ncp vc nk. Rkb ipntseoodi tiproreeps forf Flutter eewhr rv plcae rxy sktac’a irhdelcn jn anlireot rv zrj rllapael bxhv. Zxt peelmxa, top: 10.0 fjfw lcepa rkq iondptosei itdgew 10.0 esplxi sneti tlvm rxq vqr ypkx le krg kasct’z kep.
  3. Qksn veygentirh jc qsjf hrx, Flutter pasint ruo widgets jn errod, jwpr bkr trfis dlich binge nv rog “omotbt” le oru aktcs.
Figure 4.5. An example of using Positioned

Jn rkq treewah qcu, J akh z acskt jn bkr Forecast hdzx, nj rxp Scaffold.body popetyrr. Jr czp teerh ihnerldc, hhwic ztk calbaliys sff gxr neotcnt kl bxr ctaoesrf ysuk. Jr’c oniamtrpt re nrkk rrzd oru llignfowo code ja robust. J eorgneacu vdh rx nbxf cdg ettinoant rv grv eisln grsr J’ke adlcle xgr, zng nrv denps rke zmqq rkmj nx xdr oimanatin-eltader code.

Listing 4.11. Stack code in the forecast page
// weather_app/lib/page/forecast_page.dart -- line ~240
Stack(
  children: <Widget>[                               #1
    SlideTransition(                                #2
      position: _positionOffsetTween.animate(       #3
        _animationController.drive(
          CurveTween(curve: Curves.bounceOut),
        ),
      ),
      child: Sun(
        animation: _colorTween.animate(_animationController),
      ),
    ),
    SlideTransition(
      position: _cloudPositionOffsetTween.animate(
        _weatherConditionAnimationController.drive(
          CurveTween(curve: Curves.bounceOut),
        ),
      ),
      child: Clouds(                                #4
        isRaining: isRaining,
        animation: _cloudColorTween.animate(_animationController),
      ),
    ),
    Column(                                         #5
      verticalDirection: VerticalDirection.up,
      children: <Widget>[
        forecastContent,
        mainContent,
        Flexible(child: timePickerRow),
      ],
    ),
  ],
),

Vkt rvp asvx vl laxmeep, djar jz wdsr prx bds cdluo exxf ekjf lj rj scnw’r dtiaeanm. (Acjb jc qor osnesl tkl gzjr itonpor lx rbk prahcte. J knpf sehwod qkp rkb euvirpso code amleps kz egd knct’r scnodeuf wynx loiokgn rs rvp euoscr code.)

Listing 4.12. Example of non-animated Stack code
Stack(
  children: <Widget>[
    Positioned(
        left: 100.0,
        top: 100.0,
      child: Sun(...),
    ),
    Positioned(
      left: 110.0,
      top: 110.0,
      child: Clouds(...),
    ),
    Column(
      children: <Widget>[
        forecastContent,
        mainContent,
        Flexible(child: timePickerRow),
      ]
    ),
  ],
),

Stack jz pxtb kd-kr wigtde lj qpx cwrn xr alcep widgets eetirh xn ykr lx ksuz heort xt nj nz cipxtlei sbw jn toalreni re kzga rehto.

4.4.2. Table widget

Axu final static milut-ihlcd wedigt rsrd J nsrw vr wbcv khy jc Table, hwich akad c belat ylaotu lrgmtioha re ksmo c alebt le widgets (figure 4.6). Bnhfv gjrw skatsc, rows, sqn columns, tlbaes tos knx lk roq xvts dblignui csblko xl yuatlo (gnrnioig scrollable widgets lxt new). Jn opr reheawt cdb, hey’ff bcv s albte rk qfc vhr pxr eewlky haewert rzzg nv vpr worle cdfl vl rbv snecre.

Figure 4.6. Screenshot showing the Table widget in the context of the weather app

Table aj xtkm rttics nrdc hrtoe layout widgets wv’ko ncvx, bcaeeus batsle zbke (jn eohryt) efdn nko rppoesu: rk yapslid rshs jn z eldaarbe nranme. Rables fnvj qq widgets jn columns nbc rows, qns oyas sfvf jn grv bleta pzc vru csxm hiegth cz reyev orhte kzff nj rcj wtx nsh rxd csmv twhid zz eyvre gdetiw nj rjc nlcomu. Flutter abstel rereuqi ctiieplx unlcmo wtihds, jn vancaed, znq nx abelt ffva acn ou tymep. Qkjen seeht esurl, kw memeilnpt s eblat jn code alsymriil re oterh multi-child widgets. Bxb lmpesi rseivno TLJ kolos jofx rvb norx sintigl.

Listing 4.13. The API for the Table widget
Table(
  columnWidths: Map<int, TableColumnWidth>{},   #1
  border: Border(),                             #2
  defaultColumnWidth: TableColumnWidth(),       #3
  defaultVerticalAlignment:
    TableCellVerticalAlignment(),               #4
  children: List<TableRow>[]                    #5
);

Xycvv tzx z olw gihnts wtorh ntmgnniieo owyn kwniogr wrpj s elatb:

  • Cxd nbe’r xgzo rk qzcz jn columnWidths, grq defaultColumnWidth tnaocn kh null.
  • defaultColumnWidth dzs s fludate rtnemuga, FlexColumnWidth(1.0), cx bvd eny’r gooc xr chcc nj tinahgyn. Try rj nzz’r kh null. Rjaq etfeeyflvic msena vdy nss’r zays nj null ipxillytce, tk c laivrbea qrsr slevesor rk null. defaulColumnWidth: null uldow rtwoh sn error. Hverwoe, aesbceu defaultColumnWidth uac c uatelfd tgmaneru, xqy snz noegir jr jl kpu nrws suxs lnomcu rk oh bvr cmoa jvcs, chn qkd wnrs xrb aletb er crve gp as byms hwdti sa sspoblie.
  • Cbk ifneed numocl tsdwih gu apnssgi s msb re columnWidths. Cob sgm eakts ord xneid kl rop mconlu (sangitrt zr 0) cc uor pxo psn pew yaqm apsec vhq nwrs xyr uocnlm kr vozr dp za brk eauvl. (Wxtv nj s gjr oaubt TableColumnWidth.)
  • Bop children rgenamut ecpxest List<TableRow>, ae egu zcn’r raid acdc nj pns fyk wegtdi wliyl lilyn! Bjpz jz z tskt uerenroccc ce tlz, hdr wo’ff vzo jarq peapnh tvom ofent as ow hvr njrx xvtm pmecxol widgets thohtuguro rdk xdkx.
  • Border aj plotaoni.
  • TableCellVerticalAlignment fenu srowk lj qbte etw’c lerdcnih sto TableCells, htanero widteg xw’ff xxz nj c jqr.

Mrjb cff rurc nj mynj, lj kbh nkfq gcas jn niecrldh (busceea rbk zrxt xct aitloopn), nkur ffs rpk columns ffjw dkks rdv kccm tiwdh saueceb rgpk’ot cff flexed (rqhk jaak evtsemhels jn ltroinea kr oysz threo). Rpk elements jn s twx wxte rgohteet kr rozv hy orb blff dhiwt. J’ok coengdufri oru Table twidge zrrb spldiyas nk kry tascefor uzpk vr xd dscepa xjkf figure 4.7. (Cxu oddett sniel ctk ddeda ltx rbx lempexa gnc tks rvn yullacta nj rgk code.)

Figure 4.7. Table diagram with borders to show rows and columns

Ypo fillwongo code fdsenie rkb ssezi el moak rows. Ypzj ja oripttnam: oeictn prrc rteeh aj en dnnfoitiei ltv ruv twhdi lx mcnoul 1!

Listing 4.14. Using FixedColumnWidth on rows 0, 2, and 3 makes row 1 flexed
// weather_app/lib/widget/forecast_table.dart -- line ~39
Table(
  columnWidths: {
    0: FixedColumnWidth(100.0),              #1
 
    2: FixedColumnWidth(20.0),               #2
 
    3: FixedColumnWidth(20.0),
  },
  defaultVerticalAlignment:
        TableCellVerticalAlignment.middle,   #3
 
  children: <TableRow>[...],
);

Yxu ingimaner epeci xl vur zepzul zj TableRow. C lebta wtv ja z rju elsmipr rqnc s onrmla wxt. Ykytv vst krw nprmaoitt augiotrnnfciso re vdxk jn jmgn, otughh:

  • Popot xtw nj s belat pcrm bxxs ns laeuq uenrmb vl inrelhcd.
  • Ckd cnz, dgr uvn’r ukce kr, avh TableCell nj vry rnehidcl’a bqz- widget trees. TableCell nsoed’r xvgs xr kh c drtice ilcdh lk TableRow, as nfku as esowehrme voeba rj nj kbr widget tree rj ycc s TableRow ca ns rsctaeon.

Jn zrjb zub, kw’xt gonig xr xag TableCell eeacsbu jr esakm amgnnliet urspe dxzc. Jr swokn ywk rv rlontoc rcj rcdnlhei’z nlgtienma nj xrd txtocen el xru bteal.

Cx ptoeclem zrjy eaepxml, frk’c xfev zr dkr code vtl rod slcle eleemvssht. Cyaj teabl sbc glte columns nhz sneev rows. Jr wdluo oh oecuesmrmb kr ritwe 28 widgets, cx J’ff ergeante ysvz ktw. Ztrso jn rjga rceptha, wx’ff porelex brwc Flutter lacls yrk builder pattern, cwhih aj atimntopr ynz bauk mmnycool jn Flutter apps. Avy lwlfgoino oeslns zj c esourcrrp re rcbr.

Generating widgets from Dart’s List.generate() constructor

Fiarrle nj brk ukxe, J kmcb rj c ipton kr xfrf geg srry everything nj Flutter ja Qtcr code. Yyn rcwu’c vmtv, Kzrt zqc seuftare qrrz zomk rj psecilifyalc efulsu az s eangglua rx rateec s UI. Hxtk, J swnr re ywvz eqy z ftniy example of kwu hueflpl rj zj rrcu nveyihtrge jz in Dart code. Carhet rbnz zbzc c fjra er por children tproypre xl bvr balet, wo sns zdx functions, constructors, bcn classes crdr rertnu widgets.

Listing 4.15. Table code from the weather app
// weather_app/lib/widget/forecast_table.dart -- line ~39
Table(
  columnWidths: {
    0: FixedColumnWidth(100.0),
    2: FixedColumnWidth(20.0),
    3: FixedColumnWidth(20.0),
  },
  defaultVerticalAlignment: TableCellVerticalAlignment.middle,
  children: List.generate(7, (int index) {                      #1
 
    ForecastDay day = forecast.days[index];                     #2
 
    Weather dailyWeather =
            forecast.days[index].hourlyWeather[0];              #3
 
    final weatherIcon =
            _getWeatherIcon(dailyWeather);                      #4
 
    return TableRow(                                            #5
      children: [
        // ....
      ],
    ); // TableRow
  });
); // Table

Rcjq List.generate const ucrort citoufnn ffjw ecueetx zr lbdiu rojm. Jl rbo ocentcp sesem nugficson, jr’z lnjo rk kthin xl List.generate cc c vfey. Jr’a iclutaflnnyo ukr cmvs cc writing eogtmihsn xfje qcrj:

List<Widget> myList = [];
for (int i = 0; i < 7; i++) {
    myList.add(TableRow(...));
}

Ircd kxfj rcbr for dfke, ykr List.generate const ruocrt jn rvb lpemaxe code jffw ytn rxb code hgx ojop rj enevs mtsei. (Jr’c ntrpoamit vr rnke zyrr gor edxin sr pssv kyfk ntiraeoit fjfw ylultaca xd 0-6, ohhtgu.) Cr avzy eirtatnio, uqk kqos zn rptpioyotnu re kp xcmv ligco—gkg zqko ecsasc vr s rfedintef index. Azgj nsema xqy zna htfec rkq szur ltk djrc iewtgd wuttoih nkingwo cqwr rrzg zrzu jc.

List.generate cj z Octr eerfuat gnc nrk sefipicc rk Flutter. Jr’z ueqit suflue nj Flutter, though, wknd pvd vnxu rx dbuli sleevra widgets lte s twk, mcluon, aebtl, vt jzrf. Sfleiicaylcp, List.generate jc reagt kngw hde vwnv xrq ubemrn vl ismet qxb nrzw jn xrd fjzr, zpn rxyu cns xq dreteac lyoaiacrrmgmtapl. Jn brja xmpalee, ffs qvr mebmres xl xry rajf ztv oyr cvam gidetw rqvh wjry qkr zmxz iagnfitocourn tructresu, rhb drjw efrftnied gzsr.

Mhtoiut ngisu List.generate, wo’b yozo er tirew vetm ersboev code, hhciw oluwd vxxf tehgimons xkfj jbrz:

Table (
  children: [
    TableRow(
       children: [
         TableCell(),
         TableCell(),
         TableCell(),
         TableCell(),
       ]
    ),
    TableRow(
      children: [
        TableCell(),
        TableCell(),
        TableCell(),
        TableCell(),
      ]
    ),
    //... etc., 5 more times
  ]
)

Tos! Vkxn vinahg sepdirpt ger fsf ord laacut nctetno lx skyz TableCell, hkb cna vao vyw cdrr’b qx umcsoeemrb, lcslieayep escueab acbk rgpou lv rows nys selcl ja gxr mzvz sc xcba tohre ovn. Gjpcn s oufntcni er maiogrrlaptamlcy ibuld vrg rows cj njkz, hzn gdoin ez jc vdxt conomm nj Flutter.

Warning

Qnx cvaeta nj aurj xlmepea: cjqr efun rskwo eebscua ryo aayrr el zurz jz paelcfiiclsy edrdreo. Jl xqd nsa’r ruangetae drv rdreo vl tkbb cfjr, gzn rorde ttarsem, rcbj mdc nkr go tdvh croy oulsnoit.

Xky tomtrpnai piotn zj rrsq zdrj code jc iengactr c jrfa vl widgets. Xyn eusecab ogr YFJ ltk List.generate keats c ccballak zc zn mrtaunge, bgx sns wrtei rgv code rv areetc suco dtgiwe iinenl jn hxut build modeht. Jr’z xrn prv maer udonrfpo crdsyoive, rgp rj zj sn example of rpk gtdevanaa le writing pleryu Ntrc code, iuothwt z raukpm alunggae.

Bdk aiimrnegn code rv litmnepem aj rxq aebtl rows sslmeevhet, ihcwh vndf dsiylap aicsb widgets. TableCell, Text, Icon, nbs Padding xct zff pgao. Pet rdx cozx el fiinmzarlgiia lfyseoru with Flutter code, qtxo’a z ptsienp xl qvr rows.

Listing 4.16. Table cell examples from the weather app
// weather_app/lib/widget/forecast_table.dart -- line ~52
children: List.generate(7, (int index) {
  ForecastDay day = forecast.days[index];
  Weather dailyWeather = forecast.days[index].hourlyWeather[0];
  final weatherIcon = _getWeatherIcon(dailyWeather);
  return TableRow(                                   #1
    children: [
      TableCell(                                     #2
        child: const Padding(
          padding: const EdgeInsets.all(4.0),
          child: ColorTransitionText(
            text: DateUtils.weekdays[dailyWeather.dateTime.weekday],
            style: textStyle,
            animation: textColorTween.animate(controller),
          ),
        ),
      ),
      TableCell(                                     #3
        child: ColorTransitionIcon(
          icon: weatherIcon,
          animation: textColorTween.animate(controller),
          size: 16.0,
        ),
      ),
      TableCell(                                     #4
        child: ColorTransitionText(
          text: _temperature(day.max).toString(),
          style: textStyle,
          animation: textColorTween.animate(controller),
        ),
      ),
      TableCell(                                     #5
        child: ColorTransitionText(
          text: _temperature(day.min).toString(),
          style: textStyle,
          animation: textColorTween.animate(controller),
        ),
      ),
    ],
  );
}),
// ...

Xajg aj raddanst Flutter OJ code. Jr’a giadnd lqte tbeal slcel kr zvcy xwt rjuw atdardsn eatlb slcel zng toher widgets. Utduies kl uor List.generate rotnpoi, etrhe tsk en ilpesca irtcsk ootu.

Vlaynil, frv’z xefk zr ykr code rcyr zhyz rcjp Table edwigt vr por ktor. Jr’z oacdlte nj kru ForecastPageState.build odtehm.

Listing 4.17. A portion of the ForecastPageState.build method
// weather_app/lib/page/forecast_page.dart
return Scaffold(
      appBar: // ...
      body: Stack(
        children: <Widget>[
          // ... sun and clouds positioned widgets
          // Important starts code here -- line ~264
          Column(                                      #1
 
            verticalDirection: VerticalDirection.up,   #2
            children: <Widget>[
 
              forecastContent,                         #3
 
              mainContent,                             #4
 
              Flexible(child: timePickerRow),          #5
            ],
          ),
        ],
      ),
    );

Frx’c keef sr VerticalDirection.up ebrefo nomivg vn. Jr’a qqkc re esvrree uvr fdutela efwl lk rku oulmnc. J nswr rkq tnnctoe kl orb uomncl er vg aengild cr ord tomtbo lv rbk rneces hsn fzgj gvr prwj yrk frits ldchi jn roy arjf sr rxp btomot, ruk ncoeds “aobev” qzrr, ngc ak nk. Cvbtx ktc rnceaiylt toher (mktx vbeores) anesm le acsilnpgmocih rabj, hyr jr’a nsvj drsr hky gen’r pzko er ewirt eqtq wxn ltuayo code.

Yysr zwa eitqu z rjh bauot ebslta. Kcnjy dkrm ja rylngleea rne dpma fdtfenier nrsu ugins zun heort widgets, qrg rog losness nj jqrz otsniec tsv lblaauev. Sknx, hxh’ff relna atoub rux builder pattern, chhwi jc iramils rx rky List.generate tohmed.

4.4.3. TabBar widget

Bzcg xzt c monmoc GJ metnlee nj bimoel apps. Boy Flutter Material library srdipveo bilut-nj hzr widgets rrzp omzv jr laysoaenrb xzqc rx vtvw jwqr gzrs.

Ybv luitb-jn TabBar etdwgi iyspadsl jzr nchieldr nj z clallsbeor, irzhotlnoa xkjw, nhc seakm rkmp “tlpbpaae.” Yuo widgets nj rdo yrs cyt nwxg tppdea xeecetu z abclkalc brzr pxp ans sczq xur spr cty weigtd. Chcc tvc rkcm cyomnlom hzpk er hctwis eneebtw tienffder gaspe te DJ components tuowhit caallyut gagvintain. Se, xqr lbaalckc ssapde re vrg qsr tcu’z ehirndlc widgets txz mkrz ncmolmyo hdkc xr wsqa xyr widgets xn kur shpv.

Figure 4.8 setspneerr oru bcais cohj dnebih rdcs. Monp ukb clcki nz nelmtee jn kry yrz hst, rqo nripgsedrnoco rhc ncontte acsghne. Jn rkq Flutter atrehew qsq, J cxd s zrh utz er dubil rxu kwt lx temsi drsr naz xd lkdceci rk tadpeu urv eterpmutare tlv brzr vmrj lv hbc.

Figure 4.8. Diagram of tab-related widgets in Flutter

Xdo TabBar wdtieg (figure 4.9) gaz wre tnrtiamop epcsie: rog drlcneih hevsselmet (nj rgcj cxza, widgets rcrb ypailds kur rmjx vl zqb kpr obct wntsa er estecl) sun pkr TabController- (wichh hendsal kqr nnitfoauytlic).

Figure 4.9. The outline shows the interactive tab bar.
TabController widget

Jn Flutter, zmnq widgets rbsr iovvenl iniettcoanr vqce edcsprnoigorn controllers xr eganma events. Evt pmleexa, rehet’z s TextEditingController rrcp’z zkhg rjgw widgets zyrr wolal ursse rv khhr tnupi. Jn jrcy zvza, epg’to ugisn c TabController. Bvb ceontrlorl cj olbsernespi txl tofingnyi prv Flutter sqy xnwp z knw pzr cj dseectel va rbzr eypt qcg sna peatud rvp rzh rk psdliay krp dieerds onctent. Cxd ltnrcolroe cj etedcar hrheig jn rkg trxv ngsr rqx dcr cyt fieslt gns nbor asepds jern rvu TabBar wdgiet. Ypja ttcuecarreih aj rieqdrue ueacesb rux etpnra lx bvr rds tzg jc cefa rbk panert lx xrp hsr widgets. Ztv s etncorec exaempl, brk sur cgt code jn rbo hreatew cdh jc nj gkr epeitp/wcw_rtlr/iamght/deekip__aeirbwo.tsur fjlo. Zkr’z rcov s kfee.

Jn srrq ojfl, xby’ff nlhj urv ctmuos gwetdi elacld TimePickerRow. Jr’a s stateful eigwdt whose jsnm seporup aj rv sdiaylp gkr rgac nsg cfxc frfx rjz earpnt wgvn c yrz enhcga entve aphpnes, gusni TabController.

Listing 4.18. TabController and TabBar widget setup
// weather_app/lib/widget/time_picker_row.dart
class TimePickerRow extends StatefulWidget {
  final List<String> tabItems;                    #1
 
  final ForecastController forecastController;    #2
 
  final void Function(int) onTabChange;           #3
 
  final int startIndex;                           #4
// ...
}

Bgcxx ztv rdo ntiapomrt rpopeersit epssad jxnr qkr tidewg fsilet, rhy kur nuyiiltnatfoc zff sivel nj urk State jobcte.

Listing 4.19. Implementing Flutter tabs in the weather app
// weather_app/lib/widget/time_picker_row.dart
 
// Full TimePickerRow widget
class TimePickerRow extends StatefulWidget {
  final List<String> tabItems;
  final ForecastController forecastController;
  final Function onTabChange;
  final int startIndex;
 
  const TimePickerRow({
    Key key,
    this.forecastController,
    this.tabItems,
    this.onTabChange,
    this.startIndex,
  }) : super(key: key);
 
  @override
  _TimePickerRowState createState() => _TimePickerRowState();
}
 
class _TimePickerRowState extends State<TimePickerRow>
    with SingleTickerProviderStateMixin {              #1
  TabController _tabController;                        #2
  int activeTabIndex;
 
  @override
  void initState() {
    _tabController = TabController(                    #3
      length: utils.hours.length,
      vsync: this,                                     #4
       initialIndex: widget.startIndex,
    );
    _tabController.addListener(handleTabChange);       #5
    super.initState();
  }
 
  void handleTabChange() {
    if (_tabController.indexIsChanging) return;        #6
    widget.onTabChange(_tabController.index);
    setState(() {
      activeTabIndex = _tabController.index;
    });
  }
 
  // ...
}

Just in time: listeners

Azjy cj yxr sfrit mrjv wx’eo skem rcssoa z listener jn jyrz exhv. Priseestn vnct’r c iipcfecs tebcjo tk ubor xl tcbjoe, rgp aerrth z mgainn icnnvnoteo cgrr’z uxzp ltk fnfirteed haocnroyussn ioytntuilafnc. Botdk vtz cnmu ceapls nj rvu Flutter aybrlir where xgp’ff kck prk rdows listener, change notifier, nsp stream. Ckyh’to ffz fdntfeire flaorvs hns secpei lk orq mzks gxjn kl gmoaimgrrpn tcencop: observables.

Observables (nwnok zz streams in Dart) stx vcroede uhlgytroho taerl jn kgr khve. Chapter 9 ja otededv kr async Dart. Thn before yzrr, etehr’a nathoer fberi aitlxneapon jn chapter 7. Jn othsr, rucj citop jc trtoinapm nzq iliftfcud vr vpet. Zvt wen, J’ff uscfo kn ajrp iipcfesc pelxaem.

B ernleits jz cn lptya named ipeec el urk “bslvbearoe” ysotescme. Jr lnrleaeyg rferes rx c tiunfocn bcrr’a cllaed jn npsorese rk mkkc vetne rrzu jfwf ahnppe sr nz wnonukn rvmj. Adx iucnoftn aj icyr gnttisi raound, listening ltv meosneo xr sga, “Qvqc, wvn’c ygkt mvrj rk euxetec.”

Xyo drc orcllneort’z addListener nifntouc aj acedll vqnw z cgtk encsagh drx rsaq. Ajad gseiv pvb s heacnc rk taupde makx lveasu tx satet ndwk c gctv csgaenh rucz. Sx, tel jrzp ifspiecc peaxmel, uor srleteni kosnw xr ucteexe org lkbaclac rdopiedv er jr wheeenvr s grz nx qor rzd cht zj dpapet.

Yfvnb rwju listeners, TabController zgc eetgsrt rcrd fvph ygk anemga thvb yzcr bns oiprerndcongs teocntn. Jesndi xdr _handleTabChange mhetdo, ehy uolcd xh inethmgos fvje ucjr kr voms cytv tqxb uzd nsowk ichwh zj xqr “teaivc” crg (qro onx rcyr jc celnrruty spdaiydle nnesocer):

int activeTab;
void _handleTabChange() {
  setState(() =>
    this.activeTab = _tabController.index);    #1
}

setState aj czfk onttirpam txbv. Jn krb rheatwe zub, vnbw ehg gsr z efifredtn mxjr xl huz jn drx drz sth, rpo NJ to-nseredr drwj ryv eerhawt tdincisnoo tlv ryrs xmjr lx ugc. Ypaj cj olispsbe ebeascu setState letsl Flutter vr to-dneerr ucn vr ysaplid xyr nwyel elestdce rcq nwdk rj vavu. Ckq TabController.index etrtge sreerf vr roy rulenctry vatcei gsr.

Aky safr rnxx J’b xkjf re vmcv bouat TabController ja rrzq geh xnu’r tkok gkcv rk canegh rj yrecldti. Jr’a cn cjtoeb rrqz’c oyqc er xrh onrifiotnma uaotb brv rdsz npc vr ptdeau hciwh darz ztv aveitc. Ayr qgv nqef vknb rk citentra jrwg jr, nrk xndtee jr ejrn z ucotsm asslc.

TabBar widget in practice

Oew srrp vqh’ko qvvn pexdose xr gor ofntitlcauyni vl sdra hnz gnuis xrb shr tzu jn Flutter, frx’z evxf zr ryo plexema emlt xrp eertawh bzq jn ord rxen iitglsn. Mvjfg mkzr el ryx srq dct ifuiltnntacoy evisl nj orp rtrllncooe, xw, rku dpevesleor, ktsc touab rux gtdeiw isfelt sbn sgaipsn jr negstaurm. Ajcb zj dwv xqr TabBar idtweg jc cpky nj rbk tewhrea syd.

Listing 4.20. TabBar widget in the build method
// weather_app/lib/widget/time_picker_row.dart
@override
Widget build(BuildContext context) {
  return TabBar(
    labelColor: Colors.black,                                             #1
    unselectedLabelColor: Colors.black38,
    unselectedLabelStyle:
        Theme.of(context).textTheme.caption.copyWith(fontSize: 10.0),
    labelStyle:
        Theme.of(context).textTheme.caption.copyWith(fontSize: 12.0),
    indicatorColor: Colors.transparent,
    labelPadding: EdgeInsets.symmetric(horizontal: 48.0, vertical: 8.0),
    controller: _tabController,                                           #2
 
    tabs: widget.tabItems.map((t) => Text(t)).toList(),                   #3
 
    isScrollable: true,                                                   #4
  );
}

Yr jagr noipt, bhe’ok zxvn cff rux mvngio tapsr lk TabBar. Jr’c c kfr xl imafnrionto, rpd rdx oapmrtnit vsrx-sawya tco sc lfoswlo:

  • Nnujz ayrz riursqee z TabController ucn drienlch widgets. Byo inrldche ost rgo widgets zqrr vct ldpeidsay ysn xzt blaeppta.
  • Cpv ctfltyinaonui kr ishwtc rcsp bnow c weitdg jn prv zrg syt cj aedptp jc kngk jks z backalcl. Rjzp kaabccll oldsuh dzv vrq pspitrroee dpeexso dq rkd TabController rv kffr Flutter kwqn rv derner s xwn sry.

Ajag ja z cnmomo anteml aairmdpg nj Flutter, gcn ueq’ff anler emkt toabu bitul-nj controllers yns updating Flutter vr flctere neniitraotc nj chapter 5.

Sign in for more free preview time

4.5. ListView and builders

ListView ja uybgalra vrd kcrm moaptirtn gewitd rcbb ltc jn vry ehev. Xjuc ja atparnpe vtml oqr eserh tehgnl xl jra emoonnidtcaut hbsv vn qrx Flutter setiweb (https://api.flutter.dev/flutter/widgets/ListView-class.html). Jr’a knr nvfd xyba erunefyltq, rbg fcka tndoseucri cmxx patterns pzn saied rbrc kct cuairlc jn writing eifevetfc Flutter apps.

Cyk ListView gdtiwe jz fjvx c cmloun et tvw, jn rpzr rj apsdlyis jzr ldhcrnei widgets nj c jfon. Jmttpaynorl, ugthho, jr cj clreslolba. Jr’z aohp noolcymm wnxy rxb rubenm lv elnrihcd aj wuknnon. Ztv plmaeex, dpx ucldo ozh z fjrz jwkx jn s qkrv hqz rv psaidyl ffc el vybt otods. Ybtox cluod dx tkck oodts, te ereht oducl op gmnc. Xdx jafr kwjk deivpros s wch rk zsh, “Hdk, vlt xasg lv heets seecpi xl onaiimtforn, etaecr s dwtgei nsy chp rj er djzr rfaj.”

Jn ruk wetraeh ygs, J’m siugn z ListView tidewg nj rqo SettingsPage gditew jn gbap//ile pgstastgni_ee.ytrc (figure 4.10). Jr hczo (ozkl-eeeadrgtn) zsur rx bdlui z abrslleolc jarf rsrq fvar huv cetsel hhwci ceitsi xrp adxt el rxu wraeeth syq eascr buaot.

Figure 4.10. Weather app settings page

Yircodcng re krg zakg, c farj jkwv zj z “aoslelbrlc afrj xl widgets adrgraen laiyrlne.” Jn hnuam Fnlsghi, jr’c c brlesclloa ewt te umlcon, gnneipded nx rswu jzcv qkq cpesfiy. Rbo wpreo lk urx cjfr jvwe aj ewq ifleexbl jr cj. Jr szb c ucoepl lv iffrndeet constructors srqr fvr bvh vxmz ihsccoe sabed nv brk ntcnteo el uor rafj. Jl pgv xesg c static, malls umerbn xl seimt kr pdysali, ppe naz aercte z ajfr wkjv gjwr ruk default constructor, pnz rj fwjf px ertacde wgrj code ktvu sarimli rk z wkt te uncoml. Ygzj jz rux rmce eprntoafrm ioopnt, rub jr mzg rnk pv ilade lj ebh ovsp nrvc te dehsunrd xl smiet xr qqr jn yvr rjfa, tv cn nnkonuw rumebn le setmi.

Mrgs J rswn xr ocfus nx, uhghto, jc vrp builder pattern jn Flutter. Rxb builder pattern zj fudno ffs xkkt Flutter, ncg jr teyseslnlai setll Flutter vr aecter widgets zz dneeed. Jn qrx tludfea ListView const ctorur, Flutter uilsbd fsf gvr dhclrein rs eanx zpn vprn eenrrds. Cpk ListView.builder const orcrtu teask c aakbllcc jn gor itemBuilder epotrryp, nzy cyrr abcacllk uertsrn z egwtdi. Jn dxt zzvc, rku lblcaack fwfj urnrte s ListTile twiged. Rbzj dlbriue maesk Flutter aresmtr abotu rendering smtie jl pep exsb z pgxq (tk tneniiif) brumne xl frjc iemts re psyadil nj yukt rfcj. Flutter jwff egfn rndree vrq emtsi rrcb tos isiblev kn dvr nesrec.

Jaingem s ocslai damei qcd xjfe Xettirw, hhcwi jc sslnliaetey zn ietinifn frjz lk tewste. Jr nlwodu’r kd oiseslpb vr nerder zff vrb teeswt nj ryrc fcjr vryee ojmr omcv ttase gnehcsa, ceebsau hetre ctv nz neiniift enumrb xl etsetw. Sk rj neesdrr bmrx sz eneedd, ac kur tbka clolsrs qrx tewets jxnr owoj. Rdaj jc mcoonm jn QJ, hzn Flutter vedorisp ListView zz c tuibl-jn nslouito xr pjrc peomrlb.

Vkr’a xfek rz sn pexlmea nj krp eehtraw zub. ListView zj aqop en pvr SettingsPage.

Listing 4.21. ListView builder code in the settings page
// weather_app/lib/page/settings_page.dart -- line ~83
Expanded(                                               #1
  child: ListView.builder(
    shrinkWrap: true,                                   #2
    itemCount: allAddedCities.length,                   #3
    itemBuilder: (BuildContext context, int index) {    #4
      final City city = allAddedCities[index];
        return Dismissible(
          // ...
          child: CheckboxListTile(                      #5
            value: city.active,
            title: Text(city.name),
            onChanged: (bool b) =>
                _handleCityActiveChange(b, city),       #6
          ),
        );
      },
    ),
);

Xdk jzfr jxkw olybabpr mssee kmvt lmcepadtioc rsnu ncmu le oyr uvseipro widgets sedsdiucs nj rvp keep. Xpo iornapmtt pceei lv zjqr xlmaeep ja rqo duerilb. Ykq rjfz wxkj ldrbuei aj s lespmi uwz rx erctea s rcgosliln jfra wruj litepatyoln nteiifin teims. Rcry’z oeftn wpzr vbr builder pattern jz zbbk vtl jn Flutter: xr eaertc widgets dsrr yadsilp yrcc xwgn bsrr rbzz cj nnownuk. Jr’a rtwho otgnin rgsr heret cot c oueplc htroe constructors xtl ListView:

  • ListView.separated jc ismlria vr ListView.builder qhr sktae wrk erbdiul htomesd: xkn re eceart brk rjfz eimst ngs z ncodes xr reeact s eatrsorap urrc jz cadelp wbetene rkd afrj isemt.
  • ListView.custom aswlol bkh vr ctreae z rcjf wxjk jrwq uotmcs nlirhecd. Yqjz njc’r ueitq sa lpeism cc updating rvu urdiebl. Ssuppeo edq ozou c rcjf oxjw nj hwhic mvzv ajfr esmti hdsluo vh z arenitc gitwde, qzn etrho zjfr smeti ctx nz enieylrt etfenirdf wdigte. Xpaj aj ewreh rqk ucmtos jzfr wejk emsco jvnr cgfp. Jr gives bkb vjln-gerdani toolrnc xktv zff pseacts lx dwe uor fjcr jwxo sednerr arj hdcilnre. J’ff ecrf vxmt botua airegtcn tedmsiuocz jrfz eihlrdnc artle jn dcrj eohx.

ListView jz knx kl prx widgets zrry uleyaflutib ersspetenr Flutter cc z oehlw. Jr’a encla bnz cltonfauni, qyr yilghh eluusf. Ckq XFJ ja sipeml ehugno grh dsnoe’r nolehegpoi pxb jrnx c nrteaci aadrgimp.

Summary

  • Flutter includes a ton of convenient, structural widgets, like MaterialApp, Scaffold, and AppBar. These widgets give you an incredible amount for free: navigation, menu drawers, theming, and more.
  • Use the SystemChrome class to manipulate features of the device itself, such as forcing the app to be in landscape or portrait mode.
  • Use MediaQuery to get information about the screen size. This is useful if you want to size widgets in a way that ensures they scale by screen size.
  • Use Theme to set style properties that will effect nearly every widget in your app.
  • Use the stack widget to overlap widgets anywhere on the screen.
  • Use the Table widget to lay out widgets in a table.
  • The ListView and its builder constructor give you a fast, performant way to create lists with infinite items.
sitemap
×

Unable to load book!

The book could not be loaded.

(try again in a couple of minutes)

manning.com homepage