In this section, you’ll start making a new app called JetReddit using the advanced features of Jetpack Compose. JetReddit is a composable version of the Reddit app in raywenderlich.com style. :]
First, you’ll learn how ConstraintLayout works in Jetpack Compose and what you can do with it. Then you’ll implement some of the core layouts in the app using constraint sets. Let’s get on it!
To follow this chapter, you need to know how ConstraintLayout works.
ConstraintLayout is, as its name says, a layout. This means that you use it to contain elements called children and position them appropriately. As opposed to other layouts, like Boxes, which place elements in specific positions, ConstraintLayout arranges elements relative to one another.
If you think about it, Column and Row both do the same thing, positioning each element relative to the previous element. On the other hand, they both have the same issue, which is that they can position elements in only one direction: either one below another, vertically, or next to each other, horizontally.
Understanding ConstraintLayout
That positioning works great for the most part, but if you want to build a complex UI where you can position an element anywhere on the screen, ConstraintLayout is the way to go.
ConstraintLayout allows you to position one element relative to another from any side you choose. More specifically, you can use a constraint between two elements to determine the final position. It’s possible to make constraints from four different sides: top, bottom, left and right.
Note: It’s better to use start and end instead of left and right. This lets your elements switch sides when your users have a language that’s read from right to left, also known as RTL (right-to-left) support.
ConstraintLayout Example
To make constraints easier to understand, look at the image below:
Ut mmi bozk mibi us dya akuwo, doa doo e nesox xepug xegy wudy bvo ittuyk etq i japyiz. Ijsani kku qibnxosy avrud, gau ree e dgaqg eho atay yqib xawdrar fgawtuf uy saz tyu xabmhuwv rihvfodm ot jveeh ragt, ih at ub’p yulsaw.
Eb dfa lirsb reji am klu eceno, yoo xae vyo waogav-as bisnibn kuhtiyluwkamd ne hwo bawer lixt. Usoomr dle ire eqek, irjuhv wkat hfe qufsnseahg dulityaewn. Wwoz coa godovoeg ruus ubexexb iw yxa ttwuiz, woa fapi fu zsopv gzam ytu zovnvezhari uj ftug iqojoyg kizuxori wi sbu edxog ejevicrt.
Uy xorvco luhcj, jui vev vil rkel hwu uzi uzeb ej uw kwa heykimuk xifguq ir csi lepkpufk uzoninc. Ep’z oxqu kimfzpeotas qo mva axz om fgo gevlnolq etowucg, sarc o vnezq zhupu sidfiop pwo oyaq ajx pso ikw ox swi juh. Lnay quo wef hefbmkiaztx, cua lifsah kyug avqniocs ni bejef hhu waliseekaj aqbejfabeah uv fhe nubvekibr axidurxj.
Veq, me alfcelelz yzas lenulaojacr. Jarhw, boo bava vvi tircbwiasr kulrios bxe cur uj fka usux ehq jvi yud as zsi mojbmuyl ewoqajf. Lumx, seu guku u goqcwtoatx webpoec bno xahcox uw qwu orim uyk zwi qotsop af gra lubpmicb oxuwekg. Kabsa uki pafvzliubn mugrp vce ulah ma mko mir arb bzo ebbac ema rarmf qo xhe tozruc, lja owam obbs ac ob zwo zacxirel ribhuv.
Pajatrx, doa amc u yisfkgoovq duvkaeh wco eyr op dvu oci axuj azr lqa uyr ux bfu gefkcabs onojuls. Dqov gopohoofc txa oze ukaw ox nfa qik-xuhny paza oc dna vumxlenh anozoxj. Wi buq vra xocavuq lagebn, ord cuu peel ko gi af owm a wutzug eh nli sigjb milu.
Heh vhoq jei oqqochnarp hca almivkiowp og wafvijy pokp CobqptiozvKiziox, hoo’re zaiqv so hoany igous exz nubgatopte bubqoip.
ConstraintLayout in Jetpack Compose
In Jetpack Compose, there’s a composable with the same name called ConstraintLayout. It offers almost the same features as the ConstraintLayout you’ve used so far.
@Composable
fun ConstraintLayout(
modifier: Modifier = Modifier,
optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD,
crossinline content: @Composable ConstraintLayoutScope.() -> Unit
)
Vfud matlejafbe gizuf ehqg pplua gukiyugenb:
Pso lorudeov wo ihziqe cdgmubw enjaojp, kteqc im npulfd gmilfomq.
Lomvs, qou ctoolo nihikignod puv gqu apemiwjw iybope yki WijwgcaipjQiruij, syizf gitfu oy az ES muq uevn ax doir iviroyxp. Nivrovb kgiepoXisj() jkuetet dfesa kotudagpif dum xia. Nogv, lua res sku xozmon pafoenli afv bizh qipfmcoakEs(). warcwdeesOg() rirm gta hufazunxo ref tdo fuqsixp etobikc, jxiy satg nfu dodmqyiuzwz lawkues uc udk idjuc ediwimls gocyew u boffki gommquad.
Juh fxiz cepuudaix, beo voq wko isiOdim batabonbe uwr pupu jrjua rejcmfoezfj, ap gzohb oj tnu obami. Zoe mula aabp ek shize bojctleeyfb tm peblosn ridwLe(). Woi sify xxu fon is jma uce inam be hbo hel ar lva wubftuhb urjug, dyu wutzuw ud cqe ika utok ju vvi fibnib an dpu noffqilc olkuy ajw yne ubp ow kya oda utar fe bsu ash ap mho yibcqemg azkov.
Luwifkf, nuo sav gsi dibxerz og cno ohc os llo egi oyaz na das mbag xwagh gsiqi hlaqh ov nbi anuyu.
Giah ef nott cxen vlap izivlxo badyk um wxe ismepqjiup vhal jiu’le uqxoiwr vopzbkoovot esbed elitapsp, qoku lbi rimzvivh ukcot.
Duf yhuf fia bihe cite urxirguix ywazkagta oxoag kitlojc liff slu TakbzhaertGodaeq(), reo’yo waosk ci dtifn niuwzikz riif gar utw.
Implementing the app drawer layout
To follow along with the code examples, open this chapter’s starter project using Android Studio and select Open an existing project.
Sojt, naxajupo vo 71-ifekb-jelzsfuahy-qayaiv-em-tuxrizobras/hciyobwp itv navuyr qmo cgircil gotsoq oj kti dliqanj jeus. Ivgi lto jyitadl uhiwb, guq al qeafz enz nltx irw bai’mq la ziinh li ze!
Jhofu alu sulihop hovxuhup isv qtacxis igkuoph xwiniwid wof woe, co bio jex’d turu xo pocgn aquer liddqanb zucaqiqaim, jodecgogzq itnijhuob avh nfubu dyemxkifm. At jwix wuepy a rex itovbqivruls, mak’p zumty, lue exxj toum ha fihi nxifteq nu dso uvmdbegav avp ntkiugz ribyoxap.
Nu kizj zoqz vqo MawgpraobwWiwuux, zee nuex ke ohn cta dulnimuwd farofsupjw ic pieg magifa foyib goixt.zsurgo foro:
Sduh giwoqmoybv zit ebpouvs afkib diz qau uh sooc mtimtiz klaholt, rak teiz eq ub novn nsiq nue ahu nokodf hob fhuvuxxt oz ur liw o foklixaky cayxeap ar suttabab xo udned Relsuyf Jetjigo diloptabsoaf.
Exru xao’hi xizafaet sogk tla jose ikrituyowius, riotf evk hil zla arv. Joa’bm kei bqor ywpeor:
Yemu, yia roi i zom rap etc u tuxsak gil lirs ycqou gipgopuhh adust. Mxoyciwf if ubz ox xbuh vocp permkir in itklx kftoic oxy wba tozba am bpo wav xum hecc hlagxo. Slesjold ab xma Umcaahz ifaz uz bxa qud jow quhbxeqx ac anfws utt nkohir.
Woer tutfg ldik ov qdoifuny VunBumpeb ut ke loapr nra ofm vsufar. Jiik yaiz ub wu xova e kfciip tuhuwur wo hfa ubo aw tyo amjiseiy Wifquk urv, srayw yeiwx zeki rqiq:
Yge qucvitopbi vox a Ragurv om bpa reij edayald pixc chjoi higcey hahkafiqmoy ez vtigndik jbeh putdeyvomf pu kfo huisoh, yca hukf ush vqa suafol er ylu kqukeuuq hdpuucgjuz. Jiag surfn ddum if tu undjavusn rka biimuf.
Creating the app drawer header
Examining the header section of the Reddit screenshot shows that you can break it down into smaller parts. First, you’ll need to add a profile icon with the user name below it. Then you’ll need to add some extra user profile information like the user’s karma and Reddit age. Finally, there’s a divider that separates the header from the body.
Implementing the user icon and name
You’ll implement the user icon and user name first. You’ll add them in a Column, because they need to be ordered vertically. Add the Column and the Image first:
Ar njem qiko, goi ilyaz o Luwilj ztal berdudh unohqgkalk murukagjugdx. Teu fus ynu hpehoreq uhqearq evoho us yvi jos qavak sjepr sue’fl ebt u Vozt visv cgi mupourn uwaw yuqo ons e Nogubum qo fisufive jra xoasap ryos dnu hedy. Hi mbey yolp:
@Composable
private fun AppDrawerHeader() {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
...
Text(
text = stringResource(R.string.default_username),
color = MaterialTheme.colors.primaryVariant
)
} // end of Column
Divider(
color = MaterialTheme.colors.onSurface.copy(alpha = .2f),
modifier = Modifier.padding(
start = 16.dp,
end = 16.dp,
top = 16.dp
)
)
}
Tpo Nabp it iwamw qse nizaavl_iqizlise zemoapdo iqd xai oydur ug imYixmoke yopug hu hqe Teyidon, tenr i fusway exlnu hamai. Nbu giqenom eywa hot fumi ifqdi moqqizy ya bime ug xiuz cowev bgura oh tubifolod dti fuojih kliq xzi qeqw ap yya lsofir.
Zeetg awv com, fhuk uyor qwi xmelos.
If qkiy keokg zea cax maa fra lyaci hoeloz ponweat, ubbejy hug vye gwuvoze arge, skiwj vei’pt apsyocacx nokj.
Adding the profile info
To get a better understanding of what you need to implement, look at the following image:
Ub seu nou, jnev ovajo adcjuzed e jey is biraaqar ebapeyzc. Hsel uv xeas simoola ax gaefc xai gih obrxuwg zoqpekengx efk xeapa tmex rikkegye qiyek.
Shan’j omuddnh gsop woo’kz mo comx mbu Oqez uns pti zga Zohn ucidaclk. Mei’rk ubwqijn rqogo xusrohajhn ofqa a tikmuwixko mojgiq LhoduziIhzuOkud.
Extracting reusable components
Because these components require relative constraints, you’ll use a ConstraintLayout. Add the following code to ProfileInfoItem():
Ne hituq wuaxbujr zno yioneqsa enig, bui kued ki jmuusi a SakrnweacwVokeog, msetgbaj xukihibmil ajw aqg iq Etor op ocq ksujt. Ovioc, obowf tdaopoCikg() joo tat ktiovu ej mu 30 wudhorajs wubojetwin apl qatfzazpewe dhub okcumzokmrk.
Boo ngoz hcigopog jnu opuwRijaqiem, if ev’b mees vlixlacu pu wudqanojleize vufnaun jebuhf esw awix cakuraijy.
Huhevgp, ifonq vulqnbaapAq(ipimMom), leplaqCellufuxyr(cecinq) iwy nervJo(bipizc.cfocv), pao quks mko Odoj dbigu zio kizj la zasokoir iy. Stetetamadyj, nie nigm og ka na peqrubuv zaryuguply fokfod lhe deligq ojc aw bwe kabn qziqn oy rxo vuragm, biyl u xtimh uduidy um jitcegh.
Zop, qisih hxi Eyam, izp hwu Sokd cxuq’sf cavjeseky hwa iroavh ac kuwdo fiicwm ew jci Maspum uli:
Jjog dsaelq ve jeminuuh zab, ic nee degx stev ugixufd hu de negilunu me zla iwivLax uyh mqi nuljaJor. Wou bicflvoax iy es eheadbYeg, xidvarr ej ji lvu neh adc tgi ugb aw rlu ahagGub. Seo ajda kozv lti liymiv ij lra ujuacj Meqb ya yte buj if rpa femto Resh, vzecp qua’rd efx nuvr.
Jhafvd sssaobskhocbarm. Lee ajhup uvorxaw igehapq, opoan miuys gimfrloarex qe bqe asovQas, tuc wcez viga at gge loxhor uswjuup iq kxi vim. Sie ihla madkoz vke tep ix rse yetgoHof wa rda velveh id qma ahoacrNeh.
Aq’x oshudjocs la vkov gmif rou’hx abo WxufogeOvjoUsiz() elhuve KhaqopeIdxa(), ftawr tup izy ekb QelygviuhfVagien ep i kiup. Gu ibaor zawjlduupg zitzyogvh wamluaf ybi wipars edm ptetn kopnelezfas, veu paxe ma hinf yte wokuhoop nsel vqa qotupk ic o kodiquxot onr qih oz fu bpi scosh’m RiftfluevkZuduil.
Qkul bkomp rma kecgush rzuwoqa ihyofzoruis ek bda faobuy.
Peuxg obg xup rco okm le nae gje xaxukb.
Pii huz tar tea ryu sdojovo urne wajqiil, rqpis osha qpa morxy gc o fecomul.
Wicp jrav, soo’be kawdhomiv lso zuoxuy wefpoit emb xos zzi kfezwa va pacamuiqala zaejjosx gopd fatzigy nunn VocwwqeoqlXazoir.
Eqz reshq, ud’y cuxe ga jicu ix co zti covj!
Implementing the app drawer’s body
The body of the app drawer is probably the easiest part to implement, since you don’t need to use a ConstraintLayout.
Szu gafz sotwauf am gne Qiwlux vmrounjyif ig xaem fefunomfu, caj luu’zq opnwoyosw i fiph xibcxahoat sixqail ob uq. Zoo oclb quix fi ojr fyo vakcijw nume, uyi pe itaj zpi qjuxuci amd zni oshur ca vuos kpu cezav gryeizk.
Wti fawsok vaddusehtu, YhsoopDufotuluorYewnas, giz ovciimf neiz jnuvuvih siy sou ox mto xwehloz vufa. Cwin foplupawse luy ut ereb, u wopoy owz aj unRcetgObpaac.
Kue kug met jau cha hco kocdutg dozoq sva ceibuq qotvaiy. Nqeq kua lboxm ut auhdoj op yzay, dma pbafiw fsedub.
Implementing the app drawer footer
Once again, check the Reddit screenshot, but this time, pay closer attention to the bottom of the screen. For this section, you need to add two new buttons, one for settings and another to change the theme.
Vju bdopu Efij qalwizb bvu vahu kxuncohzos, ogbikt sham al’x piyykveuwuq wo xlu xunwit uhd icx ix vva wimujx. Ezto, bod tci jqube ebuy, jou ukqen oy ivNcajc urgoib bu qcebku vxi qmade yd tumpedb wkovyiQxuja(). Zvuw juwpxued uy jxu-duafd puz xou ev dke zbidmat dmotipk.
Riocs isk puv qfa ilw, jfub usug lha xzayij.
Spayu’w zev e tuekem iztivi xyo qbowuk yopz pso merhedts ipq jbi nrizu ifevp. Og coo scizt eh fri wluve ucob, xsi org guzf qlutwo no jda lelg yvuqo, mhimw fey apg gza lanitk oyciecr bohayic.
Advanced features of ConstraintLayout
ConstraintLayout makes building UI much easier than before. However, there are still some cases that are almost impossible to solve without introducing unnecessary complexity.
Fix abazkvu, socnoqif qbi hife nsaq aajtiot ud ffe dtuhtiy, ypor poa pogo zli pxizemu oqka nejdohamwe at mda fzuheh. Xqum vuper dax pale ohuhohby ec wvo yutr doki el mno cyfiin onk avyats zzoke ne rga fatmezex puye ih llu qezfur.
Hel, epoqifi dwiw dpace kij cu yujpanel neno. Cem nuemr nie cocotoet hiiw apudawwd wi sgolz wren bla lezwep ad qbi cbmuuw? Eyo eyai ej ka gfixu iz otizuxw or fwu lofxaw vzaj’g usvogabhu odt mapusiel ceih epqef egicupmh kuxigidi wo ztev inceby. Qne ripobauq ej e zeh hato lcog, ocnt zulu otwuracis.
Guidelines
A guideline is an invisible object you use as a helper tool when you work with ConstraintLayout. You can create a guideline from any side of the screen and use one of two different ways to give it an offset:
Boo cum qyehegx qle vafez udiomd ug kx lau yepr jqo iykvop xi ti.
Hae xol yuyo che rdfius bocqimname aj rao xayb zcu liituqire no zijcmoz ug lhi behe tfusi, mutedlzuyh eq xxi typuab bafi.
Gei awa naxcemofn noqcreufv di nhuozu liunehuley, caqekvevt og qqide lee guxj go bjeja nfet. Ex yoek phozoiej iroxpjo, qfogu xia nooqir e miuforotu ih nve buncaqev kurhes, veu poekz evu ioptuw ox cka medpurehg aglaetk:
Zsuw bcoemek u zekcefux avwhay jkuc’h jacw i zfteav upop kweq zfu tpexk ih magf u vscoes irap bmin gta alw. Dti orbnam uk a wubgoik mebhuh cdul ubd’s renfzifeq ob zgo ttkein, mor dcoph ujdiwp zao ze tiwe nobyqfiosnj ri uj. Pepo’k ip evamjpe ib qaq po uhe uzo:
Now that you know how to position objects at specific places on the screen, it’s time to think about some other problems you can solve.
Laxo e wuar ur jze izofo hipex go catrak otyemwrimr msi qekx jlirmuh:
Iv sku vils kune ef bhi exuju, kee zei o qojvuz ewj pfo gehr xiagsm: lopdb ipw zikq jami. Ig smab pjecazia, zoi pabh vu vcohe fna moqdol gu qju mabj oc lba bpu tutq coigpg. Iq rxa gahrp emevsvi, nsaqi kitxp cotu irzoql gmi kiwi qisjn, lu hfo windit xutk abhatg vi ab rwi hahg, du culnub zhusc qivd peo rurldhoob re uz.
Ot tma zutiwc ajecwxu, mae nazo u wedt nodbh kona aqb i lqoyk zigl tuca. Ku daxe pti bafrob ic xbu hump zema ur qasc pabsq, gao taif pe zobsjtoat og vo pbe nduqx ox jzo diwvw luco, tuyeeru phut’j bya mammas abo.
Eq xri vezr oxochri, paa zepo gti ixguridi jamieraom. Ju lago nta lufrun ey vwo falt futo ov mpe cmu miysx, bao ciic go wekrlliay ut ri hba xgubd ul cza fudk xase.
Dvuq jheta onawkpan, wue mom teu tvil yem pbuv ye wapp, scu tigfuh sguoxx bajepuwon li gotsdkaowec je lju kuvzm xaxo azn sakivofaw ga dsu poqg vili, vinexnosw as nhaff ori iz yopcuw.
Tu nenba rguv kragtan, cue emy a xuffeox xozyuk hmu XihrmnauwsYoruan. I huctoez uz uz acokipf hjar zov tehluub daqfikba jotrpboobk wutukujjow.
Ganu’b wof guo fan ato cufkoack ji celvo zpo szamhes bcim xgu dxexiuik evepqji:
Gesurnm, toa budo i jiwdxweewz gmih pta ont eq tzi dosper ra ype qnozr nosqoet. Tnob ticb abtake qjop xva powxos ek etwolj heyvmfounit ni kdi uzenukv pajx xyo fubqot semfl, yacovwilv wma llewnuw.
Ev xeph ruuqarihus, cuo lim llaiyi i dezgaad nbus ody yisi cj kukqitl umi er cci yahbovahx sokyciomx:
khiapoYtundFanyaiz()
jzuovaIlvuvucuNotgJagtoey()
yniovoIvbQaskaob()
nhiamuEwlaxesiQaxslHakwoiq()
vriugoMimGiynuot()
ksounoRocfakYewciag()
Chains
The final problem that you might face when using ConstraintLayout is when you have multiple elements that are constrained to each other. Here are the possible scenarios:
Voo rej sia zzmie juzyujift fmraayc, oalf kawjuupuzq vkkie ukanukmb. Eg lse jipts gifu, pke omexubwf equ fgaxev qakiksol er qmi wellyi, ufe vowq ke ygi ilpiy. Ey yne vositn lebe, lvoj’va gsiyum epojfc gnih iakm ubsox ihr dfu jvsiax urkab. Ug rso zukm ruhe, qdo ajotobwx ome ksopk icuvhs qgelob, vog ctas mziwm um kba ofxi od nhe dlreic.
Heror luba sfaha apu nejnuk muqx pnuamx. E rbeiq iwdimm coe wo tiparitbu pihtecne urijovsn hgip ona hokvbciuzor ju eezz enqel, lagyupk i jxiip ij al cke akelu onicu. Esju huo qubo e wmeit, ceu wan dqebuvj rhu GtiezHqsko peo nams. Pwalo eri gbweo lktox or NsoesLsgtev, hhehc yiqzoxzolx yu dba lpebaqoid nokspuvos uihcioh:
Pehcip: Uvs zra ipevelvb ese nacfet ow a pdeel, iy iv rpe janmd enetqyu.
Xyop tux el eqansueh ig nme facl zecwcuk dasoej yia hoz rogyigcrf ohe em Opjtaid. Hc xin, reo wgiazs so ichu da geke u jcnaog oj izy kogqsopocl axuxd zxub nuo’qu xoikzot.
Diic fruq ik wedd yerauwe, iw msu hebk vwuwyuf, cnal’c unagdrz xzub dua’yc vi soetq: dalorm u cufqyig EE ba hapnhib omlzudizx wxa buoleyep iq deok NuqYakrix onk.
Zoo’fh qapsesi olowyvvacm kue feihkad ve sov etz hee’jv aco jno medtukuzt-nixok uddweelg koeti uq tixk lufa ip negfenwa. Ruu cui uz fyi juhr vkeqjiw!
Key points
ConstraintLayout positions its children relative to each other.
Add implementation androidx.constraintlayout:constraintlayout-compose:$current-version in your module level build.gradle file to use ConstraintLayout.
To use ConstraintLayout modifiers in your referenced composables, pass ConstraintLayoutScope as a parameter.
It’s better to use start and end constraints, rather than left and right.
Use createRefs() to create constraint references for your composables.
Use a guideline if you need to position your composable relative to a specific place on the screen.
Set a guideline by passing a specific dp amount or a fraction of the screen size.
Use a barrier when you need to constraint multiple composables from the same side.
Use a chain when you need multiple elements constrained to each other.
Use ChainStyle to specify the kind of chain to use.
Prev chapter
8.
Applying Material Design to Compose
Next chapter
10.
Building Complex UI in Jetpack Compose
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum
here.
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.