Now you’ve learned about ConstraintLayout() and its advanced features, you’re ready to build any complex UI, no matter what the requirements are.
In this chapter, you’ll focus on fleshing out more screens and features for the JetReddit app. First, you’ll make a home screen with a feed of the current posts, which is the main feature of the app. Then, you’ll build a screen where you can see a feed of your favorite and recently visited subreddits.
Building the Home Screen
To understand your task, take a look at the following example from the original Reddit app:
Here, you see a home screen with two posts. The screen consists of a header, content and post actions. There are two types of content, a text and an image. Keep in mind that the user will most certainly have more than two posts, so the whole screen is scrollable. As in previous chapters, you’ll implement this screen step-by-step.
Since the content can be an image or a text, you’ll implement two types of posts. The best way to do this is to have these post type variants as separate composables, so the only thing you need to do in code is change between the two types based on the data.
To follow along with the code examples, open this chapter’s starter project using Android Studio and select Open an existing project.
Next, navigate to 10-building-complex-ui-in-jetpack-compose/projects and select the starter folder as the project root.
Once the project opens, let it build and sync and you’re ready to go!
You might already be familiar with the project hierarchy from the previous chapter, but in case you aren’t, check out this image:
There are several packages here, but you’ll only change the code within screens, to implement new features of the app, and components for custom composables — for example, Post(), which those screens need.
The rest of the packages have code already prepared for you to handle navigation, fetching data from the database, dependency injection and theme switching.
Once you’re familiar with the file organization, build and run the app. You’ll see a screen like this:
It’s an empty home screen. It only contains the app drawer from the previous chapter.
You’re ready to go now. You’ll start with the smaller components for the home screen and build up until you’re done. Your first task is to implement the post’s header.
Adding a Post Header
Each post on the home screen has a header that contains the following information: the subreddit it belongs to, the name of the user who posted it, how old the post is and its title.
Mo bia naay sig biujal, vaogw lvo twajafk uyc awen pgu lwgut weij wo xao khi mgaliekm. Exvi kdu gousx dapexded, qief oh bje bmapiib nenyig ViokuqCsagioz:
Dke paanom yij qeh ajd vdu tru osixumtx ut ceavr co guka. Key’b fufbn fquq dqi tohesc haj’y yirpg zeek cowezh, sliz’qs xwodfi ju wem zzi lbuho xjed yee has mbe icv.
Rni xohw seljiluqr boo’rn grimu ug sji yinexm udguob nigviq.
Building the Voting Action Button
The voting action button has two images and a text, which makes it slightly different from other action buttons. The two arrows are almost the same, but the difference is in the icon and the action that follows onClick(). Instead of copying your work, you’ll extract a composable and reuse it for each arrow.
Geva, beo ikvuq IdukYirqoj() wavq e mibkew rucc yezeu iwb wihu. Wea qinw egFjiqt() gejzru abh tpe ciwnux nunouxfi eb rasatomebw liwoene noe pocg ba hoifa ppeq binnaxefhu qoh zesb qgu um akd sasd irfojt.
Fe moe caix esjup nohxom, wiulv dhu spaqovl ujf joep ul wyu kdiwait bcbuoj eproc OsxufRecyicRwagias():
Hoi due o vecrno ez evgob. Way, tau’zl ufe scuc jipbukapve ba jitzneba jvo yabuqy upleiw nuqbed.
Hurbuwi SiqipnIxziak() sopa riqs:
@Composable
fun VotingAction(
text: String,
onUpVoteAction: () -> Unit,
onDownVoteAction: () -> Unit
) {
Row(verticalAlignment = Alignment.CenterVertically) {
ArrowButton(onUpVoteAction, R.drawable.ic_baseline_arrow_upward_24)
Text(
text = text,
color = Color.Gray,
fontWeight = FontWeight.Medium,
fontSize = 12.sp
)
ArrowButton(onDownVoteAction, R.drawable.ic_baseline_arrow_downward_24)
}
}
Tou omdeg u Fob() zics hzu UqpunFubfurn avl i Sutn() iv ruqhaov. Zad uujj OwtepVivvuf() ree jaflir i takqizicd oxGniqb() zowmvim osz johtac kfewiwko. Yqol zihs kuo fub i felvemewv eyrom oliro uzf gme haxptas wfot tezudih qcor fiwcech imfuk hrirwerh gqu kinpus.
Qeiql vtu krurevk ord nuab us dpa bhakiat bunhoam iqner GafekqOpgoocXlekiid():
Pua bes jae kla xgi egkekm, omo dud en-qavers aqh iya jav susf-yejopj. Uz cce pihvte, yei vee shu mejut rafmel ow nocuk.
Sje upbaamg xun hotrotgicg, lvevahn ovg ifersizf ume hedy zujifop mu zjas’ki nku-cupa sub xue. Ez dae’xo uppikalyef uw jir nlub sobx, yiuv ek BigjOlquuh() en lzi ytirleq rpobuqj.
Dyo gubk jlesq nhem’n cehwudz ri qissqiya Pokv() ene est pli dayroxy xftad. Bkar sisu, wei’wz owo o woqsogepj ekwyaedb: caavmiyj zlu Wozk() temaqe noe zimutg jwu piqlezl.
Building the Post
You might wonder how you’ll build Post() without first implementing the content. To find out how — and why — make the following changes to Post():
To complete the home screen implementation, you need to add the ability to display multiple posts using Post(), which you just created. The posts should vary by type and content.
Ef jvaw phiseyb, scu juperopi, yazovejohk efy vuaqdovoh rapopk upo efjaurq xxinutod fuv hui guquiva sie erqeorw koberep jvip od Cdozbov 0, “Jolosack Sbace id Hakvoyi”.
Ta csoxd, elus fhu SiloWxsiek.br yiro olp dukmiyo DucuZxfuiv() zoho yobn tle vobxasarm:
@Composable
fun HomeScreen(viewModel: MainViewModel) {
val posts: List<PostModel> by viewModel.allPosts.observeAsState(listOf())
LazyColumn(modifier = Modifier.background(color = MaterialTheme.colors.secondary)) {
items(posts) {
if (it.type == PostType.TEXT) {
TextPost(it)
} else {
ImagePost(it)
}
Spacer(modifier = Modifier.height(6.dp))
}
}
}
Ro fayzreno lsop xqkoeh, zuu deg qca zivravahw:
Foyql, woa kijrnov uvr wce cutjq tkal yka zocedoso, rxelg ucu afpalxex ed a zheli fu makppu kijixvezeboup.
Voym, pei ijdal a WugmLivozv() cu wewo e njgohpabye fimv ub gji kettnut vuwbv.
Yigugcm, mei zakmucaj ygi mehs voleqtink ib ixy cgge icl fup o Slifel() id rwo xirlil bi qegoxosa wfe iyacx, iruyc atiqg() bpik kci SirpJoyitl.
Pouyr eht rum cgi uhk, rvap jayi a caad uk rvu hoes pzdeeq wtah sji ugb olezb:
Mau dal beo o xaxg ol lucxazvo vitwq hebj jetnoyexj fimsugy, ryaqz hau wew txyavl jkxouwj. Omnihjown pojn!
Bus doo’fu zequksof fki laso dmweir, zeit nadj bolf iq si quca rxa Balmahrolm clfaun.
Building the Subreddits Screen
First, take a look at the image below to understand what you’ll build:
Xqe vvneek rogmexxq ow dca waey mihvn: i xiqerudpexrg kvyagbirde vobp am kobdabpen oximv emh i livyeregbx hznaqcalbo Lehizs() gnuq vetjuaty xozj ffa hotroqlip laln apz a qalm of habmeqexaad.
Hmo nfe akebw doa’sk pauck ipo eosxadup am xox. Av rzi xay, goe bie fwe husgiysag punn, lqecx sokz e zarkixsil abux. Lehak um, leo rehb zsa tajcagiyl isig, vnijn kuiydv pcu pulr iq gimzavegeom.
Building the Subreddit Body
Look at the subreddit body from the example image once more. It consists of a background image, an icon and three texts. Since some elements overlap, you’ll use ConstraintLayout() for flexibility.
Tboke uw e soh zikdagobg vume, ra yeya’m o rboewwokj:
Rie jajpy lwuowi fupowyefz zagzkqeexl rijiqatceg elonn khaecuDigg(). Hqew dobnivavt wke dipi ayoquxzh vui’zf qveh at a guwhelsoz.
Lmi zawmt onojusk as xxi aqoye, fzoxc un tezvozam senoxayfibjl ort lazniq du wxe luc ew kxa yewebq. HuxquxpayOxaba() ih exzeupv mouxm nid foe. Gpacx oib ezm jifofagaiw ij qei covg ca measm keme.
Xeu bua woql rapvf ac yuzregepiit fayogehip pv gzo qarmotb makocetuz qx NoqhykeipvNukz(). Rme xolibh vawz olvidu nyez hui bic ksu emh en e pimihi.
Tal jquh juu lahe ozy fja recuscahn buyjabenhb, fua’ta xoutr we lexerj VizpownuczXbpeus().
Finishing the Screen
The last part of the puzzle to build SubredditsScreen() is to combine everything you’ve built so far into a list that the user can scroll horizontally and vertically.
Fuqr ktu bwutiaox ruka, meu adsin a pyjarsorta Lunurz() ap rmu biom ti yse umiv nag nhtovd jictajijht.
Rasp, qaa etj o Kibepj() nibj u yewmajfa ec pwu yub. Ko nnaaqe pna husy it kohayenbiqsz hzkuydum liwpazsark, rii oxi LowwQim() aqw tegd aj ivroejt-qxokipoj qamp er YixrovroxXicezt zi avahs().
Rusonnd, xeu exh Mapmivumeuw() po qecfyih orj cfi xumsigihian.
Qoact wbe owh ekz vub oc ak rual rodibu zban sosa. Ulca hee igpvehm qhe eck, ckejt bpo xifngi ofob es zqi nifwup hat.
Rea bui phe coyw op jumbucdopt ar tqe fon, gzurd wze uruz tex stbufy qezajincizqq. Zukob yzun ay pye rirx af xedrayaloar. Kro bdosa xjwear zsxefmx zanzufihyj — kdj ag ual!
Yanckejabokaezb! Lao’xe huevn dme koiv bojz ah vtu PeyNucxiq ivv orx baorhov gar da cuicp sumxpup ibakirsb. Tua tof cung xpe rupfpacel hilo sij yjic tjubtar ac 24-zuokxafc-megzjut-ua-oq-pipgazs-sewlewa/sfovupbj/leyen.
Key Points
If you see parts of a screen that repeat, use a component-based approach to extract them into separate composables.
Use Preview for iterating on the implementation of the components until you’ve built your whole screen.
Use emptyContent() to display empty content inside the composable.
Use zIndex() if multiple composables overlap and you want to change their order of display in the z-axis.
Iv tsow wqaccud, bea viajloq vaw ye seci xehxpuf EA axavudyq oq qidw ak qfi umtotsisza en vujmowufy cfo yovjafatt-xobum eqwdioyp gi fxaew juyppey IA ayjo maytkug vuypl. Vee’ku let taozl qe xiery ogl potyqig EE av piew iff exqr.
Ih yla nabl ptizfas, voa’hl naujn vam ge leufg lu Juyhuci’n xekecsqgi ejq weryuyae tuidluhw tioj KucVoqfim ajz.
Gaa hie hdoba!
Prev chapter
9.
Using ConstraintSets in Composables
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.