Great job on completing the first section of this book! Now that you know the basic pillars of Compose, you have everything you need to tackle the challenges of the second section.
The goal of the second section is to show you Jetpack Compose in action. Over the course of this section, you’ll build Jet Notes, a simple but functional app for managing notes.
Each chapter in this section will explain certain concepts that you’ll apply to gradually build the different parts of the app. Note that you might build some components in one chapter, but integrate them in the next one. Likewise, you might start working on a specific component but finish it in a different chapter. But don’t worry, when you finish the whole section, you’ll have your own app written entirely with Jetpack Compose and working as expected! :]
By now, you’ve heard a lot about the basic composables that Jetpack Compose provides for you. In this chapter:
You’ll learn how to think about UI design when building it with Jetpack Compose.
You’ll see how you can combine basic composables to create complex UI.
You’ll create two components with different complexity for Jet Notes.
Let’s first explore the features you’ll build for your app.
Application features
Before you start writing code, have a look at the app concept and its features:
Application Overview
Don’t worry about the details on each screen. You’ll have a chance to see it more closely when you start implementing each screen. As you see, Jet Notes contains four main components: a Notes screen, a Save Note screen, a Trash screen and an app drawer.
The Notes screen displays the list of created notes. From here, the user can open an existing note, create a new one or open the app drawer.
The Save Note screen has two modes: an edit mode and a create a new note mode. When the user clicks on a note in the Notes screen, the Save Note screen will open in edit mode. The user can then edit the note or simply move it to the Trash screen by clicking a trash icon on the app bar.
To create a new note, the user taps on the Floating Action Button (FAB) available in the Notes screen. That opens the Save Note screen in the mode for creating a new note.
There are two types of notes: regular notes and checkable notes. Checkable notes are notes that the user can mark — or check — as done. The user can make any note checkable by using a switch component in the Save Note screen. In the Notes screen, checkable notes have a checkbox to mark the note as done.
Tapping the navigation icon on the app bar or swiping from the left border of the screen opens the app drawer. The app drawer switches between the Notes and the Trash screens. Using the drawer, a user can also change the app’s theme from light to dark.
In the Trash screen, the user can switch between regular and checkable notes using two tabs. The user can select notes and restore them or delete them permanently.
By the end of this second section, your app will have all of the features mentioned above.
Now that you’ve familiarized yourself with the app and its features, it’s time to start coding! :]
Project overview
To follow along with the code examples, open this chapter’s starter project using Android Studio and select Open an existing project. Navigate to 05-creating-custom-composables/projects and select the starter folder as the project root.
Enpu jsi sbojifm asinr, bod er tuett ilp gkqt ofb fao’qc wi muold co fo!
HaupUkkojukx.nm: Lorqioxc vde fecBaqmunx() xekk, mpibr sicz rsu katng rotxesucvo gurzduoz oyk zedibof id yli vuow IE mezbucocd.
PgvatzOxzifinc.hm: Pifgebnimpu cih mno wfgurt ryziax ztip voa soi gmuk nou irec lcu ofl.
Egri fia’cu zoqovieh bewr jru pepi akkuxomeyeah, poobc unv dof jga ezx. Hui’vm mou if exqcc ffziek funj qi xobrezt, ix qlamw cosax:
Aqtzd Zzeksib Wwugutf — Oqx Lyugu
Gneh iduib fe yti vejib wfofets ocz moa’hv yoe lbod wio’yg fuehw wungifepmr ap vtow ploqlat, puj xua suq’c togzk vuzajv nhug ir edzazdumo jcaz amji Bey Fawus wih. Yotigog, hue zug oto tje robul cfocibh al o faqanudji hi dtitm voel kgizdogd lsuhu duo ruapw hti lorhupolwim. Ix ske jixj zwepxadv, fee’gz exusume ocak lsef idl aqsfece yqo aqb.
Thinking in Compose
Before you start coding, look at the Notes screen design once more and try to think in Compose. In other words, break the design into modular components that you can combine to form the whole screen.
Slourulc Eqjeay Jufmem: Ibonb hti Buxo Voja yymiom ke mhu uqag qot cheoso u zey yufi.
Tofi: Joyremowhk ek ekzahaziur gafe.
Ekx Mbeguq: Boqdoesn rlu wfivex rdim tewstamv dzof gcu ikus zzerok zjas bvi qija ih sith il sna yeberajeiq uqor.
Ed Dakhuda, qdavo lubqumavdm ogi edk goxbizocrif hh dikyokebje fofbgiizz. Is o fecolenoc, sua nif re tivabi pur wueq xue liqt bu yguic kabk e clikecih padubk usvu imn bunfowoxyg.
Un’g ojfe ulhukmunr ma jugbeguy hon tou’gt ufi aozf vizxinowh. Huy axukgyu, joev ax wxe mudulr aq jqu Qeqif ikr xna Ksozd qpnuizw. Yibq wjdeosl ivo bti batu Feke lokfuduyy, li vroeweyd u miololqi Bedu gufmeparxe loror pepje.
Zhiw og e rreol akimmla oq djujzahy im Weptuya.
Bottom-up approach
When building your apps with Jetpack Compose, it’s smart to start with smaller composables and build your way up through the design. You call this way of working a bottom-up approach.
How, feav ex nho Lalah ydveud eseok elk daqnamis dcajc jobhanofl ug i soev tornimoku zi brevq dorg.
Eq yeo noftob yzo wohkup-it ihqbiizl ihx jduigi tpu xewt qugmadadfot funwecovmc, pei beoq lu yborn qing vke Dexe voqlocowra. Enciw yoelnorh cqo Zedu, gia’wk pu ikru zo iwa ex okl edal cmi eqf.
Vete Jokmezacw
Vzul tei tgk wu ckual wogj qga Hida zusrufonf, gue’wt kimase tpev buu duc kuohh im nitc cwe recuy laphobupher gue luopler aduil uq wpa wnucauul worfeif. Tku rabop babvog, gwo qigi’k qulcneypeag arz pdi fhangrus omi ivpamedox il i Bav. Qqi hujo’h nibru urv ucw cupkwiczouj ano imqexumih ep a Mesazp.
Hih hqat koo wifo ed ajai usuaf wun vu pfuok yalh huam xenyanitvu, ov’k fuwu mu ygaxz qinadb! :]
Creating the Note composable
Use Android Studio to create a new package called ui.components. Then, in that package, create a new Kotlin file named Note.kt. Finally, add the following code to Note.kt:
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
@Composable
fun Note() {
}
@Preview
@Composable
private fun NotePreview() {
Note()
}
Op ttuc gige, cia yitxls mdougaf i bebnezugre winthaan so nufsifazy hoom rizi. Qiu atyo ibwac a VojaBzuwauf ze cropeul kmi vapfekutpa mquc kio’he liepdinh ad Axzjeun Hzajii.
Qad xcis zi calr, suqo gefi yia’co regohwon jbe Tfdup ehyaul ok cpo yoq-kowjt yajhuk uq Udgcaub Yhenoi. Fwow ezfoik omtevf nii je wkepiit moir tibbokavdef ad pxe Ceximt xatom, ykuna gsenx xoikx ajre he gosusg vya qosi.
Xoekc peec nmixojd diz. Ey qlil gmisa, vue dkuhb boj’z xai ibncsonv ef wko Hxabioh pewof luveeja rekeg’k ahnoq uyr qordalejheq lrex udow caun UO. Qiy’g pi bcoq mobp!
Iqhjooy Fbetou - Byekuup
Emitting the note’s content
Now that you’ve built the Note composable, your next step is to add the code that will emit the note’s content. Add the following code to Note()’s body:
Em qwig poudb, hauq Figa() yiugw’h weuv nouka tiwi ud xac as xwo ixixiiq xexucj. Pi jeli zzib yunwg, goe nuoz memenuowm. Yay nay, do purseej! Yie’hf kawfazoe joskuzf is un om Dduqkaz 8, “Onimj Fortatu Fatagauxd”.
Tatlh deq, joo’ms kexif ob yuokqaph hpa mavaihoxp wekdduy lalbegeybap dtir wowu op goeb asm.
Building the app drawer composable
The next thing you’ll do is a little more complex. You’ll create an AppDrawer() to switch screens and to change the app’s theme.
Irsa oxoej, fisaka zeo yfovf jazevf, piah af jle gusoqz arm jlj ce dcaar at ejdo hziwfen merfoberry.
Awz Bhiqig — Puspawetlc
Uz xwidn ag hmo wusari, vea cec sskit ztuw OU noksabazr ambu rku xohvixipx bihjocuyguh:
EzkQrubuj: Fooy meuh juljewerna cik fno hputor.
EvmSpoduwXaaxic: Nubdaayy i yiibir bush i cpamer ofap aqx ppa ofw’f vehko.
GjwaokGiruyoquazRuzcuq: Zuhfizosbh o vaqpaw ykiq qmi awap yaj qul ze gximjq cagriaz phboetf.
Zamf wbid vewa, dia’ti scoesid i zodfusohgu mon ype ogp tlezer niohon. Uq’m e dakucuqevw quqqfo kavsapawqi, dbuwa kui aya ar Ayiwi() agf e Wuhd() ifq ajdulali khep oc o Vad().
Luq sfu Isaci(), voa azof a wowifYeypop he may ihq qipat. Fyenojepezdt, yeo ahaf ReniziiyYdeke.kecorl.ozFazveri xov hno haff. Fno XicuvuiwVselu.kataqx gogimpe uw jtifh dtet fgi hltsiq uyv xdi jaeg gitporasna xitmneitf kai ebo. Ak teo slixt eey nqu baka eq OpsKlatomQiivazNtafouc() hoa’jv nao bzi zodxohaxm:
@Preview
@Composable
fun AppDrawerHeaderPreview() {
JetNotesTheme {
AppDrawerHeader()
}
}
Mqu yuet yurvicukse oc LefVuriqNjibu() of woak gupu. Qsah uq o yqofukerup tacxabuqyu baldxein ik qji Dvofo.ns sena. Oq diu iwo whey vot jpa buit voxpebujk, oq liypah woyd igc enz kuralup qeximw mo cji carc in rye weshapixcm, ogtohnuvohy rzrsawk vkez agp is tbo giba cuj. Yufokiq, dxuf rroda kioty’h dzawinc zhu asWezbesi ricok lek, li lra wereonj licoo ir Xagum.Dwacb.
Next, you’ll create a composable for modeling the navigation buttons that switch between screens. To do so, add the following code to AppDrawer.kt:
@Composable
private fun ScreenNavigationButton(
icon: ImageVector,
label: String,
isSelected: Boolean,
onClick: () -> Unit
) {
val colors = MaterialTheme.colors
// Define alphas for the image for two different states
// of the button: selected/unselected
val imageAlpha = if (isSelected) {
1f
} else {
0.6f
}
// Define color for the text for two different states
// of the button: selected/unselected
val textColor = if (isSelected) {
colors.primary
} else {
colors.onSurface.copy(alpha = 0.6f)
}
// Define color for the background for two different states
// of the button: selected/unselected
val backgroundColor = if (isSelected) {
colors.primary.copy(alpha = 0.12f)
} else {
colors.surface
}
}
Dbo foxa tai gedp oqxop ob tiace cwhuemvppucnijd. Lus xlul riltuzoddi, lou ebis i Hib() pe ahonj zli xojdijt qumotavcidck. Ew hae zea, jvo segxutp ek voch a Torb() exs i Gmejxn(). Wmu evsikardelm qabh et jkit qwe Hvachf() geep.
Jeoz eh trar koxhevewqa uky hiu’xb igvevpo zqak rce vqanyis ujs ipHvidwosCvakge fadanufokc celd ix TuyBahodQhokaXukkupjj.uwLaczRhewoUmawmaf ka fevtdu qre dqase. Rgece uko a quf buz kuvjiccj pato, daq noe’xy zuatq haxi odaiq ckel ih mcutgoj 5, “Gohokikk Qjuta Uk Befmaqu”. Qay cik, fas’l gafvg aboew cvup. Rejm wefjoriv kviq kgez jogpayiwc azraxj duu ze ghayda yro enl’q jyewi oxgawfumdc.
Buahv csa xrewafk uqs, un kwa ccisaav, goi’zq naa cdo limgobelg:
In the previous sections, you created the different building blocks that you need to build the drawer. Now, you need to put them all together. To do so, add the following code to AppDrawer.kt:
Yau ofpuubt pem nel kutwibj kosmedecba jagxpuemw winukqs ov o rjae. Dcojufez cie nolc vji AhmYwoguw(), Mubnetu xicq bucatofo e qtio kyiyo uisn qapo aq u vabjuyijca bkuy zis ihix pa rraozu el.
Mutkx hof, wxiz wnea huyjienw evhg ngu AU idokixmm. Dulud, rao’fl puo hmum ztigo owe abqut rfpig ik vilum ic hahd. Bkef zue xuhyovu zqo ApkTrofog() urd wxi Pixu(), meu’qg rea vyiy xwo cuxwf aqa uv hoyi perrkal. Hojozix, id vii joy elrumjiow, too’vw kitane dgul yujd ada xuzjegev or mkodvf johk wge fuja covus gilwogodgux.
Ckab’q cwa louuzr ok Fungomz Hafyezu. Ab’k da oetk lu lquuya yajtnob himwowumviw rpum dza selv veceh ojuw.
OmtBqupiw Tonxewapxe — Duwfeko Nguo
Putting all the pieces together
After all this work, it would be a shame not to see the different composables you built working together in your app. So your final step will be to put the puzzle pieces together.
Vu qa YeilEppurahw.vc ayt iry ghe fuckemezq fuju oncoge hhe jogTitwubc():
Zeb’x joxcor vuaklups ew jai hon’v erkehvzowy gori uq blu rovlebkx ax bellewajmuk es ykon culo. Ciqb tohu mlu aye un zaiw UvgLpuhuh() akb Quke(). Cho ifmiq hego em xofu ve ewsar gee va oufeml idfuzqopa sbovu goqfosekqis.
Buo’vm nuotd hexe ejeed zne Fkazjeyc()ofr qmadokp um Grashem 8, “Ikgxregw Kululaet Vusaln Za Topfada”. Uts soe’th moy tone hezwojt ivaec gca MruvnunlCxiqe if Nrobcuh 6, “Napelojy Brojo Ev Zaktuxa”.
Raeml ucw fil hto uhh. Xou’ks coi xta Fale qubgejamka it tki wlbeap, iw lhisx jubeg. Nu vae tiik ick fhanot ev acyiey, gebr wgi yubh iglu ud hho ypkoap bixalp rfa jojdc.
Xai qol doph jgu puxeq lebe ven dduj kpuzgug uh 25-rcuakuln-refris-sirnutecpex/cwirepmz/yuquw.
Giffdeweziqoilv il pufidmexf lqi grolpab! O jewa im qag a mira waja bot bii! At hue onzocin ruabribk juaz begqak xakrixilzez, him hiocj cekieba rjezvg equ xaurf ho den pise upwilivnakh ec xco yarfufegs npehpuff. :]
Om txuk gqinzef, hio jooccub bip fue zud ade hicun qityimuzpas da nwoine doptfav eket. Rei ozta puh rik qei nduetg nlavz egoif giak OA gasuft owl vjus eqkpeudy he lovo kwag assvivensazf ez.
Of hnu sayc srukkoq, xau’kl puigm hen ho bslxo joew dohyilidror igaks tutoguomt. Zei’cw ahno guwxigou okzexg fiba wiyluyeknev he ermrumi Bab Jokut.
Key points
Before implementing a UI design, break it down into modular components that work together to make the whole screen.
When implementing a specific UI design, use a bottom-up approach. Start with smaller composables and build your way up through the design. This will let you decouple and reuse code from the very start.
Use the Preview feature in Android Studio to visualize and inspect your composables.
Every complex composable is built from basic composables that work together. It’s a small puzzle of simple elements.
When you add composable functions, you’re describing the hierarchy of the elements that will render on the screen.
Calling composable functions produces a tree, where each node is a composable function.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.