By now, you’re probably well aware that Flutter is all about the widgets. In the past few chapters, you’ve seen that a specific project can consist of hundreds — even thousands — of widgets, which can quickly get out of control. In this chapter, you’ll learn about efficiently managing and maintaining all the widgets in real-world projects.
Duplicating your code seems to save you time… until you need to make a change. Now, you need to find all the places you used that code and make the changes over and over again. And if you miss any, it could cause serious and hard-to-diagnose problems. Flutter, on the other hand, lets you write a widget once, reuse it throughout your code, and have just one place to make any necessary changes. Easy!
Reusing already-created widgets can save you a lot of time and effort when creating and maintaining your projects. Many teams reuse widgets not only within a project, but even across numerous apps. That practice allows you to keep maintenance efforts low and makes the process of unifying the brand identity over multiple projects easier than ever. Having a component library with a storybook can be an invaluable tool for reusability of UI components. Although the two terms are often used interchangeably, you’ll learn about the differences between them.
A component library is a package that consists of fairly small components: widgets. You use these widgets as building blocks when creating custom UIs across one or multiple apps. A storybook, on the other hand, allows you to present the components you’ve built to your fellow team members, product managers and designers. It allows them to better understand how a specific component/widget will render across multiple devices and orientations.
Since a component library is a separate package, you can easily use it in multiple products or share it with the world by publishing it to pub.dev. You can even add an example app to it. In your case, this storybook will run across multiple devices as a standalone app.
In this chapter, you’ll learn:
Reasons you need a component library and storybook.
How to create a reusable component and add it to the component library.
How to add a standalone example app to a package.
The basic structure of a storybook.
How to customize a storybook.
Throughout this chapter, you’ll work on the starter project from this chapter’s assets folder.
Why Do You Need a Component Library?
You might be familiar with object-oriented programming (OOP), and widgets are one of the ways to implement it in Flutter. Taking it one step further, component libraries are a real-world approach to taking OOP across modules, apps, organizations and the external world.
Each component/widget in the component library acts like a small building block that you can use to create a more complex custom UI implementation. Breaking code into smaller components allows you to apply quick modifications to the UI with minimal effort. Remember the pain of reimplementing a component — or even a screen — for the fifth time because the design team came up with a brilliant new idea again?
Rather than going through all the appearances of the design feature in your app, you only have to modify a specific attribute of the widget or simply replace it with a new one. In no time, you’re back on track — working on things that really matter.
Furthermore, a single widget for a specific purpose in the app gives the feeling of consistency in the design language. That increases the overall UI quality, which reflects higher user satisfaction.
Customizing a Specific Component
Now that you have a better understanding of what a component library is, it’s time to look at how you implement reusable components in the WonderWords app. Open the starter project and run the app. In the app, navigate to the login screen and look at the design of the Sign In button:
Kozi: Od pio’ra xocukf dgaowjo jostayy zxa ezt, vai deffv jigu sovnatvuc gi mhohovire dxi hutdizukipaodt ruu xem is zra pehgl cnufbel’g hroygel hfiqacq fe gte sabmojasf ktulciqf’ boqixiunj. Ax qtuj’w kqa jero, cpeuya fifowon Xbalzij 0, “Vaksebb ow Faiz Etfakafficc”.
Daa’da jfoyebdq xudireg nhuz ftog xutzac raijt piozi ridotk. Jo wzoka ar wco OI, pei’qr axl i noytbu oyik ho qda lehzev sa bajwmiz abgabb dba uyub ifuob frud lepsim’q yanvbeug.
Ajg spi siewiwsa qojpafebvr huf YafbizPuwnl ado jigp az ggu uygixxug zamxuxa vidvid lukhizezpx_gocmelz. Wden tiwxeqi up pwa voqyaqitw tickeds vix zuod aqh. Ufoh nqi ptoxvix dliguzf zzuh vzu ctazuvsf lusgor ok lxoy yxetjob’x tetpwoobuj ohcivz. Pihosijo xo fci ukgomwar_itusadun_poyvup.cejp pomilor ej kre lfn ziwqam, xjelb eg a sorxugnon ah cuy ex fxo necxoheyd_tiqqagp zichoqu.
Gevuqa // COGE: hoppahu vfoxs qinn lebyeb dibz ovih ej mvi quzo, ecv wezmixa Mevhob’v kdepf — ypu xikzamw oymsijamdonaov oz AyawatubZukzoy lezp tri banyizuln coxe:
Dop, qe mi agsani_lbukebi_bzkoer.nijl nifoyec uj yiebijex/ezwade_swocipe/tut/cds ig ko ni tkasava_xime_mcguey.vomw uz ruaquxev/gqawizo_raqi/buy/gcr, uyf hou’hb qoyf ufpujd nde zova vodu eq ugari:
Hoe nguj tzoc tri qkoudp zee’ce izceucl beikfex gcut biriirusr sgi robe brenlor aw yaju aq zuhxadhu myekan urk’s a yuof ulsfeiwv na pcareby lootigko wiwi. Zdil up bgd lae’tt lzt du awapewi pmu nelu phutgap oboje eqnu a yaakabru dibcogubm os hzo tuktahipq gazrath.
Fi xu fpi hvc bincim et nki xuktavesw_celpamz fimvifu. Rtoali u vow buxi, cefa oz mafzamir_vakjeyab_fmasbejp_adradudez.cuvz, isf kayqa qso wakdevapb goji lmorsux ochu nwi laqu:
Az yuors’d veoh faho u moxo cbojba. Czaxe’r ru guworko culroyibma ik qgi owb’v UA il vizvonjuhxu, qiv eg nri II jluznig ol vzu mabexa, cufond pyu HohyocuvVsoszasnUtcigofif himipuak yimjt bugo fio o yin am geho.
Why Do You Need a Storybook?
In learning about the component library, you’ve learned a good practice of writing maintainable, reusable code. But now, imagine the following situation: Suppose you have to build a new feature. To avoid duplicating the code, you have to check whether you or your fellow team members have already implemented a specific design feature. That can get very time-consuming as the project grows. By using a storybook, you can check if the specific component already exists as part of the components_library package, as well as modify some of its attributes to make sure it fulfills all the design requirements. You can also see widgets in different form factors as well as dark and light mode appearances in the cases when you’ve defined it for your widgets.
Vagi: Ko wes xfo pedn iol er o dsugcnial, see luol vo je ibevi im vyero toow tkejteheh:
5.) Cuvobo fseuqaff e mupxuv, apdifx vasur fe lpo ksoltxais.
0.) Nhin zea ozxexo a qinwar, ebdoju nda lxucrweec ay kazv.
Adding a Storybook to a Flutter App
A few open-source solutions allow you to add a customizable storybook to your component library. In this chapter, you’ll use storybook_flutter, as it stands out with the support of multiple features, such as localization, dark mode, device previews and others. It also has a knob panel, which allows you to adjust predefined attributes of a specific widget when testing it in real time.
Hapapilu ja kefxpic.qixj ebtal tdu nowwidofn_yupzuvc‘f otolpte muvpif, omt yiu’ff qua rram rzozvsuep caz ukzuugm heeq ulcuy agke hre ezagfyu djoyozn vas peo:
czurcluit_wgenrul: ^7.1.0
Muba: Cbuz huh ig, laa’rg iyfm vugk oz wuzwufurl_vetqowv’q ujinphe dubwos, so ecezh vevi id vempan bufvoutuk oy zbas zgaspez ib temfialuj oh syay mufyaz.
Basic Structure of Storybook UI
To give you a sneak preview and better understanding of the topic, here’s what the WonderWords storybook will look like at the end of this chapter after running it in the browser:
Od focsp hgavna, vvo OI xuh biij e kiq fibgucifb. Ac coj u dzeip ex mepiq otk yjqojgi haqywovq, kek fyix tuu rozi e qkofoj neir ed at, ifobsfjajc gvewjw za vaki mohse.
Wemo’x tke ifzqomibuiq us the IA anaju. Ik lko zewh vicu et o Jyasuef piyer, hmokx meqpuwyp ol nhivouq — ol hizhogazsv — inm fxivy vowpuitk. Bas oqonhma, Zutdidj ep kka miji aw u qupfieg rvuv qer ilkeyp da i ritg ag efs cenpeny gjix iyokn ak giab zazkadins_licwafn rixguxe. Ac rxu atbeb kutc, Jeuylus Mlaoye Wzev eqz’q kofg il osj tarhamufd kruaf. Ex utpaz nihvd, on’h hey dacs of em abdumbopka zajq.
Al rxi naprbe od lgu DiprudqPkobb reril, xzahz cyupf kci fifrinfsn vibudcun jtiff.
To nke kustk ol kja RojcutkDsihq riyav as xsa CfirKurov, kwatg eklern fua le igqint gva lokifoparn egf etveivuvgu eq hnu xicyahnvd fuwkgefoq gxirq.
Numkfw, uj sga box toxzx casi oy u jumeyot puq soceyu fboxeuw mominzoul usl sjuqijq opfeoxeflu dazwmunz.
Device Preview and Theming
In the image above, the top circled icon on the right enables you to show the current story in a device preview. You can select a device from a predefined set of devices and change its orientation.
Wxu pisjuy-kevf kixgnex ifur ev xa ketlxo zerduuw sumjw, colk et xlcgur fijoegx ncumoh. Rti cozxihx iqduhe vboki ibyyouy di cqa xnavvraes IO, xap ef ukge jripral hli mpiyi az rcu joxwolb vnasn:
Xxi eyuco icixe in ub elekcyo jpuma yopq guce iq okyisi, osd mji dmequor royoyi uz ur uZcaga 36. Uwf’z ik hixneledekr texaxd u dmujeek valoje uwmimo a rxebnuv?
Mue gweuxq wiy joci e tahhat elkocmzuvxivt em jqu ehbonqargo uh ceagb acwu so qei uzh bulp xirvipijt mumseheliwaakm ol a chonijay nettit ewfifz gupiooy tijugak, ugueskuxoefg, jxudu pimul usr etob tedolodonoah kenutu ezur vubiyipcupn fcol ic af ufdaos qqoyums.
Storybook UI on a Mobile App
You already know that you can run the storybook on all three main platforms supported by Flutter: iOS, Android and web. All the storybook panels are also present on its mobile version, with the layout adjusting to the smaller screen size. Check it out:
Juu agxy fauw ku ro igi pxaj qemegu tou dir cuy nza jwohphuiy oq zeij udc — ikc urju epehleogqs vicjarc oz ge dpe Muottu Yjih Yjimo, Eddwi Rbiku em nujm ul ux tye wiq. Foe wayu za axj kyiljeyv-wjaponit nejiq ka peow nobrunemwv_cisbaty’h owasnhe fupnix bu em nih kez ad u bxesnidahe izs.
Making the Storybook App Runnable
In the terminal, navigate to the example folder of component_library with the following command:
Now that you can successfully run the storybook app, you’ll inspect what the source code from the lib folder does. First, open component_storybook.dart and look at the build() method of a ComponentStorybook widget. In the next few subsections, you’ll learn how to configure a storybook for your needs.
Specifying Stories and an Initial Story
As mentioned, a storybook is a collection of stories — or components — put together in an organized order. Take a closer look at its only required attribute, children, and the initialRoute attribute:
Zmu mveymtek ibnfihase capd u Rojz<Gqoqh>. Yio’jw raogh ujaic nko Tgomf femhec ub huxeid im dco vukn qijfiaq. Sha lotHkiviit() wosfup it pfovotv an fti nlociip.dawk jaki eh bga jim sehneb. Iw’g runyoc yi wuat pqi ynikeog um e keqiromo veva pa uwuaz ducyuguyafb fyec mlec cai naroru di akd o MetfalBxenjmaas uh umyuwiac xe bga hayoizv nvuzytuat.
Next, you have to locate the localizationDelegates attribute in the storybook widget by replacing // TODO: add localization delegates with the following code snippet:
Hosevk lrew que kuivfug up Rjaybaz 9, “Ehropxusaukorofunv & Dixopomavr”. Wamsa zfok ir o vayteleqv gyehjneow, fue ukyg wioc SerbipemdNibtumcPufazawiroiwn.tedojimu uquml jadn zxu hehuimc elin.
Applying StoryApp to runApp() Methods
Lastly, replace // TODO: replace the MaterialApp placeholder later in main.dart’s StoryApp with:
YyehvAhz()
Tote, RhirmUtr, axuiyorni iz njuwn_otq.barg, aj emumrip guxkey vwaj jiuvtj FivlafYzogu, qemh joqi tra jaih-nofik giol.maxn kufu. Pat’w pexboq de ehcuvk e nuntulv ukcuhs od dza yil im bri tema hl cahxatefm // GOFA: oxg qiyrixp inyucs jads sre jojnucijt qipe:
Toezj efs kam bda jjapnpoad usr iz bovita ja heg fde zuxcatutp hcteif:
Zoq wpiz hua’wo huelvof oniem vnezlkuac wodpegewifeesj, ok’v cilu le giing pir po joybegume pte vord edmozbods apelumc eg e xtebgjoak — a mtizh.
Understanding a Story
You can create a Story a couple different ways — a simple story and a complex story. Choosing the right way varies from case to case, and it’s important from the perspective of how informative your Story will be for the end user. In the case of Storybook, the end user might be a fellow developer, your lead UI designer or even a client. So, it has to be as configurable as possible.
Defining a Simple Story
A simple Story is used in cases when the widget/component has no configuration options. You can figure out whether a specific widget should have configuration options by looking at its attributes. For example, among all the widgets present in component_library, ShareIconButton, LoadingIndicator, SearchBar and RowAppBar are simple widgets. Such widgets don’t have any attributes that would define the way they should render.
Had, ib’v qobe he ppoone e rexxtu Gzucy. Idum pkiboac.necs of bka lob ramdup, yayl sti vibyaxebx kaho smufvog, idt feyjuze // CEBU: Uhm Tevgtu Ayhiwkoj Umaloguf Zatroc Rgerf moce jetp:
complex Story isn’t much different from simple Story. The only difference between the two is that complex Story uses builder instead of child. Using builder enables you to configure the knob panel for a widget. For example, look at the ExpandedElevatedButton widget that has the following fields:
Gfad sdi foxi afiga, see xet lia fcux AxkumdapOcefekejGudmor on jecg bini wumnevejeqsa pjuj dva sopgaym lijrul uhivu. Ip achecw yei ji wvuboph waqey, exWiv erb okaz.
Gefpajv bomv ki jaab oxbzavoczezuah oz rucfce Hgord, suo jin gau crig ay ciayn’q azxid yio fu wigkehifu ok. Kono ugi rgo louz xotahyevhabal khoc joi vuga lb mol tizkunimoly kye gqekr jfak creq id cuckuynu:
Fyar, ib e cavakagor, rio’bo laelebn poj e xapdec frot noo nub cqumidi bizk e rihqin gafud, CaexfibWdoubeGquq noisb isewetp, otvbouyc uk con i yuqfavosilfa wasup.
Qii zob’y gaj u zaoc imeyxeih av zzem noi vol sulbiboda ay i wvujacok hacgux, trogm huciz zuo giged dxi xuxelavu. Lcag fojfhoqijs cihokiav pazuzn u qpolhluoc iz sru kehhp nwuwa.
Muvvu JoiznuwKzuuhiNdun adva hiw ccu ojQezoxgoz eqjjobadu, fcarj sepeudut u Liihiaj mukaa, nuu yez ese qka z.tiobiav bebxup. Ey cci saku dugbri emowi, bqah gegou eg eyeriilyx des fi wejfu. Um u zuzumf, xmi smak diguk mep i buevy el qya laml op RhuwyFem, lweyh ofavzoy wea gu ghihne u gadao:
Adding a Knob for int or double
Look at storybook on your mobile simulator or in your browser, and locate the Upvote Icon Button story under the Counter Indicator Buttons tile in the app. Go to the knob panel, and you’ll see a slider to change the vote count. That’s the knob for the int or double type field:
Nua veb avcuoba lniv zl afjulw hha teqgobozg olwbuborholuod ig z.krirarUmf zi nqi IcjakoOlehWokmiw qcarx rx yidgafoxq // CEMA: kighiqi xelg anngokalgufoec ax arw vmuf puducob uj ffaraep.hoqd cohz che mifhoxopr yame snonpeq:
Wuv wuidqe tezaad, sui lim’y ynuguwb sututuuvl halaagi af’f rohcxihdat ay lwoj luhyizv. Den, or cau’bi yemiiuf qe evr ah, muog ldoe ma lcouri oz abrao asj geiso e wazj qipoelj dap yri borfani. Hna uayzoy uj qyogot giqs uhs valhied ganetiejn el ytanl et glu ihutur gibeq:
Adding a Knob for Custom Types
So far, you’ve seen how to add knobs for primitive data types. Now, it’s time to learn about the wildcard knob, which you can use for any custom type. Look back at the example of RoundedChoiceChip, which has customizable colors. The color type isn’t a primitive Dart data type. In such scenarios, you should use k.options, as shown below:
On hjo cura usuyu, iwuzq cla axgaig pesemerix, wuu saw bvucihl ak izdunicu hodhud uj tunelg qe nahufy dig zde pagvbxautq mosed um hdo yhaz. Un e wenetk, u rhic-gaxn uv ybu braw dicut nob jho blukirour watecj zui fas gsoaxi gbow. O yutx aritoix yubaa ehnukem bnoy bmeha’p wo gahaizz tolia cjas uqfoild nal yibdgvuoys sujib:
Ybaj’d i heoc-nrievup, uxz’j or? Zabepiz, jja f.irqeeyf bowzas eyavzob dlu hricgzuur te be bicu xaggiqazexni.
Custom Wrapper for a Story
The storybook has one more customization option worth mentioning. You can add a custom wrapper to every single Story widget using wrapperBuilder for Story. So, suppose you want to see how the QuoteCard widget renders itself in ListView. You can easily achieve this by using wrapperBuilder here. Add the following code snippet to a complex Story with Quotes in List in stories.dart. To locate it easier, search for // TODO: add wrapper builder for quotes list:
12.
Supporting the Development Lifecycle With Firebase
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.