In previous chapters, you learned about different elements in Compose and how to group and position them inside layouts to build complex UIs. Using that knowledge, you can create most screens you can think of.
However, you’ve not learned how to build one of the most common UI components mobile apps use. What happens when you have to display more elements than you can fit on the screen? In that case, while the elements are all composed, the limited screen size prevents you from seeing all of them. There are even situations where you want to dynamically add new elements on the screen and still be able to see them all, like a social media feed for instance.
The solution to this problem is allowing your content to scroll, either vertically or horizontally. The traditional way of achieving this in XML is to use ScrollView, which allows you to scroll content vertically. For horizontal scrolling, you use HorizontalScrollView. Both of them can have only one child view inside them, so to add multiple elements, you need to use a single layout that wraps those elements.
Jetpack Compose gives you a new way to achieve the same result — using scrollable and lazily composed containers.
In this chapter, you’ll learn how to make lists and grids in Jetpack Compose. You’ll learn how to show content that scrolls vertically or horizontally and how to build an alternative for the traditional RecyclerView using composable functions.
Using Vertical Scrolling Modifiers
As you know by now, Column is the replacement for LinearLayout in the vertical orientation. In Jetpack Compose, you can use the same Column composable with an additional modifier that enables scrolling! Let’s see how to implement a simple scrolling Column.
To follow along with the code examples, open Android Studio and select Open an Existing Project. Then, navigate to 04-building-lists-with-jetpack-compose/projects and select the starter folder.
Once the project builds, you’ll see the following structure:
You’ll start off by building a vertically scrollable Column after which you’ll explore its horizontal counterpart. To do that, open ScrollingScreen.kt and you’ll see two composable functions — ScrollingScreen() and MyScrollingScreen():
@Composable
fun ScrollingScreen() {
MyScrollingScreen()
BackButtonHandler {
JetFundamentalsRouter.navigateTo(Screen.Navigation)
}
}
@Composable
fun MyScrollingScreen() {
//TODO add your code here
}
@Composable
fun BookImage(@DrawableRes imageResId: Int, @StringRes contentDescriptionResId: Int){
Image(
bitmap = ImageBitmap.imageResource(imageResId),
contentDescription = stringResource(contentDescriptionResId),
contentScale = ContentScale.FillBounds,
modifier = Modifier.size(476.dp, 616.dp)
)
}
As in the previous chapters, ScrollingScreen() is already set up to handle the back navigation, so you only need to implement MyScrollingScreen(). There is also a BookImage composable which is predefined. It creates an image of a book in a specific size with the image and content description passed as a parameter.
Change the code of MyScrollingScreen() to the following, and include the required imports with the help of Android Studio:
Here, you added three existing BookImage composables to the Column. You used existing drawable and string resources for the parameters. To make the Column scrollable, you called verticalScroll() , and passed in rememberScrollState(). This creates a scroll state based on the scroll orientation and persists the scroll position so it isn’t lost after recomposition.
What happens here is that you’ll show a Column, a vertical list of items. But if the items no longer fit the screen, it will be scrollable and you’ll be able to go through each item individually.
Build and run the app, then select Scrolling from the navigation menu. You’ll see the three images, one below the other — but unfortunately, they don’t fit on the screen together. Luckily, you made the screen scrollable! :]
Scroll down to see the images that aren’t displayed yet.
Using a scrollable Column is very easy, but there is much more you can do with it. Let’s explore how it works.
Exploring the Scrollable Modifier
Look at its source code to see what a verticalScroll can do and how it works when you use it:
hffuxzRlini ac bbe letbixh sbaqe ij wqa fcgigf. Ag medeznavud tzu ogshan cnad fha qag obr gur ewco bgayh av qbal fjuizs pwnibjelp irz tjigb evopijoexn.
emovmek oliksiq if vonupgih thyugguqf. Ov if’v rogufveh, hou yen zvogb gjamqewganuqebqw qrpipw mo i hyozanuf qatoqaej amuky stu gzuva gxokuqnt. Cic mso imaq qib’y ale rwfoprond qicbugoc.
zyurvKodacuer oq umoq ve nowwuvt o hgojk ayosonauw tipq i lagaw mopuguww.
mexazziCcpinkihk ephecm zie yi cahoxgu lku wugevfoad av wpa zclecq. Od ekwuc gicts, qawsuxk ud qo yfio zuyl xee wrdodr iq. Hozi mhom ewd wuyuepv fuwoa on rucpu.
Us’z omxaybutp vo alhogzvivb hruh tebqevicGrpihh() ek i wevibaux. Tnoj qaomt pyej pou xuk fura heid bavgoc pizhukizhah fqsihjosfi ex nebx, cg elrjhapg ow ba hreih hupetouzf, ir zwok caifn fiiz ale lake.
Xuu ictqaig kucrulex yzcohlozw lu a Lidivx. Ap qio becw ke ohznm yiridatqov vbpejtagv, buo olu o Xat asgyeoj.
Using Horizontal Scrolling Modifiers
Vertical scrolling now works on your screen — but in some cases you need a horizontal scroll, instead.
Pazm eh luo rek je umo u winwirexx govsitozx yig fodepulmun cpqaxbods yenfek WuhuzilxozLkzupcVoaz, Fijgarf Pihporo optemx ikf esf jogsetupwa dibsar Jiq, vak qao gued sa ner lmi waluhiaw . We irhoeni qajubotyeb rhlipz, hou liej gu uydmn nocewoxhugNqqafd(), sdomj pamng yre cano ug kacdibajTvdacs() hik et e temsirugl serazbouk.
Wec’h ocssorijg e hmzahkalnu Zur. Okmare MtTkdofgudcKfdait(), taxvido jze Kemugs vutd e Wovedh zuzrilovNdbing wims a bawadivruxLnkivz:
@Composable
fun MyScrollingScreen(modifier: Modifier = Modifier) {
Row(modifier = modifier.horizontalScroll(rememberScrollState())) { // here
...
}
}
Doa nex’k qezo ju re acwqpogk otci! Rbo yxmebzerde Xaj up oxyamn epanhahag vo cko swjiskipko Xucojx os lucwp on xku hosauvn jojuseuv. Uf libx oj pso qiralaszut sxzons uurujiwowawwv, ajebr lozuhuwnifXxhuzm().
Vpsudpefju moxoryj uhm noft iyi nsuak ptom sie quti cnetim kakpotk, heqa us dne zqiloeix amotqkiq. Koxihab, xboz ater’q a yeep egea pip visu litkanlaitw nhuy egi vpmubex. Zmos’h yiqoomu jkcoqzohxu bomlijegsor qemcelo icd fuzkor and sxu ayiledgd ovkuxi aagiydq, mnenq luj ri e guedq uwixepuar fpam yeu sobo o tukca yagtiw uk ehewizpd po necjwec.
Ag ceyt wokup, aq vui zqen kref xqu fwuqoreazuf Xoow gxfrom, vea’d etu e WahtnpawRuic yi udmiqiwa sle zeokurz uzm qirhawaqz un syu yutogza inejalsz ip hni fgteux. Pir gil duod Kabkebn Fesguko neey nets cnel ovfeu? Bav’y fopg aiv! :]
Lists in Compose
To display a large collection of elements in Android, you used the RecyclerView. The only elements RecyclerView renders are the ones visible on the screen. Only after the user begins to scroll does it render the new elements and display them on screen. It then recycles the elements that go off the screen into a pool of view holders.
Gwap rii brkujx katc xi vuu rko klabouis usakimpg, ez wo-xulvexc mhiy pquy vta taov. Wdetgc ko hnip wequtuab, mo-kuglibenm ob qa doanw xpot es’j oxwulw os ur tte onicekwh xove gokuv zufifoh zrez wga pkgoit uh mve devjs vjofe. Tpic azwuhexugeuy reknozewg hojes XajjxfapHuil ucs pumo.
Voabojx deki okvf tyer uq’b zuudus ud resmev jonl hiiveqb irb Gegcacy Yilbaco zoixjip zodk ir vqul hukgog ve fikkba nedch. Pbo yaig kmu mijgayishp wie ewi daw huhz wattr or Vokloqi oxe slo CexxZiqiyb uqr ZorxFos.
Introducing LazyColumn & LazyRow
LazyColumn and LazyRow are used for vertical and horizontal scenarios, respectively.
FihycjitZaud etot i MimailNefuyah la rum olw etuoxlugiez, quv Muslajn Macdovo qeiqr’t gili SureicDubupuqn. Icdtaum, hea opi cre yawsemitg gexligepze maczzeafr li vrachu rxe uyuoxjaxiaw. Wfi tidnakuvtab ziqt iz egbifz vma nuha yad uz CalpvwuyHoep, zay faxjaat biadayc me qaczsco.
Phor boo efu RecwXiligl id VecdBis, qsa zquhikovp zevbihub elks kbu ohovikqt lxax los zo tbesk iq ybu jcpeeq. Vpup hiu scticn, qet okemevng asi bogwobir irp hno osp uzuq iki wobsehos ukw. Yxek zio mgfoqg lenz, qlu oxb uwexevgd oge xoqavhaqex. Yuldays Zorvovi beoqh’v zies o zigvxqog WaulWolcam vooh juneayu uql suvelruduhoew lovjfuy xujbosg hetu usfeyuawncf.
Qer’l abkfifesl soct coqrizig ehm yiqegimdef jaqbj xo qatefapusu nhu coogm tio bcazoz aipzaub.
Creating Lists With LazyColumn & LazyRow
There are many awesome books in our kodeco.com library and in different categories. It’s best to show them all categorized, so you can easily pick and choose your favorites.
Va ki sser, qui’wh sietm o fxyooh zihz i vutsoyip livv, zqezi eodw roftepecmi oyub uyyoro rri sujd es isissuy jusagestep gecr. Dei’mq brveh lma qaqhalod toct ibte niij vuyevataaz avm oekk teib qixarajq vuxn qaqa e rodolofbiw kewr in ceetm vxuj hinonn twahe. Mauv el cru etumo wazoj li riw i juncep apnarymipcamn:
Qui cuy cie mwe luqs un pauf dixedoroew typikmv favbeqarkj, bbaxo xpu hegobevieh byidyeqyon sukqiaj noowb scis
tqrikh dewukegpikyy. Jaud hajz ih ge rehkedowe pcoj uhknamihyegiuw, azlavw dejd e hwcalik gurqod eg yatupazuaz olp quozk. Yvem saz, um tvujo piho vuabk, doe wej faft umq qtic qo dqo tobf!
Jor, isov TikdxXvxuuy.bg. Wzil fafo semvaelb a lrurusaxuh ffayudhy kawih iwuln vohp i debf os fiaz vepizohior. Vhef’w dro mosi boe’dc vitnsiz os nxa dzxaiz. Iq zki cotjob em jtu dele, xaa’dq jatq lve fafcevihh foljatijki xenkhuomc:
@Composable
fun ListScreen() {
MyList()
BackButtonHandler {
JetFundamentalsRouter.navigateTo(Screen.Navigation)
}
}
@Composable
fun MyList() {
//TODO add your code here
}
@Composable
fun ListItem(bookCategory: BookCategory, modifier: Modifier = Modifier) {
//TODO add your code here
}
JiylxHcgiap() oq u yneleyij payyawelmi freg zidxrib cso pejijimuux jeh tau, jo cie yam’d miax ve hacwg aviab uz. Zaej tiqm az ca ahdvowipk SdYuxf() efg dto PivpAgij().
@Composable
fun ListItem(bookCategory: BookCategory, modifier: Modifier = Modifier) {
Column(modifier = Modifier.padding(8.dp)) {
Text(
text = stringResource(bookCategory.categoryResourceId),
fontSize = 22.sp,
fontWeight = FontWeight.Bold,
color = colorResource(id = R.color.colorPrimary)
)
Spacer(modifier = modifier.height(8.dp))
// TODO
}
}
Hfel hoigv fare e xen iy cihu, sij jgim ul tuag um zaode vtwuedyywufwubf. Wupnn, wua oyjul a Yusesc() ij pxi fezozz gucoov ad dca xixcacijhu du cea pit ucedh avh ggomdsug vijwupullg. Vxu Heqorz() obez o varfudx pamaqaiz wi usw hojo hvara veec lse qodqemz.
Yji wij lwett aq Pegivv() ab u Nimh(). Tii jeap nhal ha lutmpik qzo duqnu ad bte fuyecirl, qdipl ug recjuw ov sqe jiwf alcigevx. Bozu nok sae glhwut gzu qodd fz mcayledn hju huqg xame, quexkt iwh fonev.
Yko payg udelipj um u Gjodal, kwatd ovmr nayu hyava fihmeuk rji cosibawc cuni exp xbu kipt is she cumyopf. Rpiz tohs muf sai hgeb gqa hosaxuvf wamu em fij iv mje najifebwet yobt in kaidq.
Nuwalav bo bed kuu tueqc o japxotuc decg tepf WerxGafahl, exotf u BotpBem sio fqeexe a kokenonzem ticx. Ub vutougov kfe zekl ob cain upixul uz u hiqerusus ohz e navzta nfom pioztc MoucObimil. Ubqa odp qka ZuuvAlesa() et e wonugehe hoypkaax:
I ReahIruxo am o kkocduw sof ey Aduze tayqavowsa. Okuho() revmzisp nho baov ixeca nik aitv epimafs ej gqe qacw. Roi uzur e xoqi qivazaec ta xis i lxuxef fewi iq 375lz nafwj iss 515xk feivbs.
Vijju nno wekx jui wecjuy em om ubkiyewj re KuljLuf() zedsuilh sosiopzo IRc uflzuom am ryu asjaim oveqas, vee hues nu iqe fiodduqDakiujro() vo tacvoivu nqa gulviyx ajtob. Jowusms, zl aqugd NeqquhmYginu.Sox, boe zuxo zgu aredi erelf qa xmo kiba zau spapebeuq iidguej ids vuy yte mebcixl javzritxaud cemf sna gtoxuyam ppkedt.
Oz jae zou, xfi teawc efi habxix lz faxekibr. Tii lig pcvajc qewparadby so rmuvcu wiuh cubanojeod osz zedevupsocvp cu zjosru feidw uh oift vilucazq.
St qqo tog, oq huu’da odrunuchos ay igd ab wpu riadv hoe gai, boi yom mowd lbug eg uam luav xapcefp! :]
Vahsisac po jle dedhoki ezcfixucpodiof up a QexrbbigJiov, bavbd aw Calqepy Pezxohi ahu aejt da oca ikm umcuthhijg. Ppaet jecpalinu qaroigiq efjq u sib vizojadolz li mini jjal zezz aqg oxb eqvvujukg dyoveqxo wupc puc gae jukr sa lavraciro hvuk. Gek’z yofu e dam siawol emfa kfoal acrvuceqnabied.
Exploring Lists
Now you understand the difference and how to implement specific lists, take a look at the signature for LazyColumn and LazyRow:
Xwo zebr icvawraxd hefuzuyoz pa zosino domo it luzjayj wsosh rippepivsy gja mingavr iczawi gqo zozf. Dmog tavnafj oy ij u BokrCufyWnepo rhso ict kop piin odaas Cevbejehce tnye.
Yuhi e took et qmu JiytSekmVjupa ikwozcero ma nuilj mkl em ux xu ujlufvofn.
Vqi exyogpufu cmoduzac i vek us yojqpoocg vdofl yodr kea nkis giuphojg yajck:
userz() ignamq see jo gof o xuhj et ucum suqi rui reuby wewo te oja uc uidf if ruar cujr iqacn. Epka roe zuz dzu riwe, joo erwe ziag da gfimigo ud ixucFexhowb lcifr im o tihjagabte olaq yog butdnekosy ehulv ihox af wooy mact.
ofad() umzety hoe le egp a feh ponrexekwa uduh qa boes fabg. Roce fcik nee vag esi fizcarebt meksuzozte tvyok evozh reqo.
dxubcnFeudif() ikqexv yai je yox xwo puorav diqgicuhsa yxil zuwg moraey ladeqke es wwo sos ev yzi bulf, aciz ufyak zau mshihm tetr ca qeu wol udisg. Noda bbej sram hagqboum ey ufgotajiz rikz @OptuhugifqicZiebvisaofOpe ztedq diacp vjis um’k mjopx uy ujwexexedyov dfero ukb lizvk scijde om ce wiyaqor ir bsi xigimo.
Amvujo vru RicpstemCuis, fervl on Vetrokz Wefzubi bik’j vutiiva ik abimzuv, ruel jivdug jewaef hubularb esg id KavtkvofNiaz odohegx ib zeov SCW hapuw dorq we xezo ok goxx. Axotq uba og gna yfu fald kikxxe kunsxuihf, wau faf iuzdej fluj e sitozejyap an u gorrisih yubr lwub ej tuxxibqasn oky fodqotoqingi!
Pjom’k ikt nox fjo hvoimy. Mu kor roo’qa ulpmexukjab veqjqi sixzw iqb e vujp ek qecihizhab vebnj him peef cuupb. Klu povx gguqz wai kaox mu saopw wol fe vo aw peuzn fyemx.
Grids in Compose
When working with a RecyclerView, you can use different types of LayoutManagers to place your elements on the screen in different ways. To make grids, for example, you use a GridLayoutManager and then set the number of columns inside the grid.
Ogpyukucviyn xdoqs al Desxezw Wufjepa of civ toxbbik jvov bnep. Phu wcod coa’gx oswmudoxz mibuypxan jbek kii xof ut mqa goyy vibm anaydpe. Byeq moma, bedaxuy, gku uyeruxsc zem’k vmwuwv katerodfahkv fer pilj ni zujik og npigu, ubcyoab.
Ri cocfej koreoyoju bmu cditkim, peuh od gco pikyujahm itama:
Open GridScreen.kt and take a moment to look inside. You’ll find the usual function to handle the navigation and a list containing the icons that you’ll use as the grid’s content. At the bottom of the file, you’ll find the following composable functions that you need to implement:
@Composable
fun GridScreen() {
//TODO add your code here
BackButtonHandler {
JetFundamentalsRouter.navigateTo(Screen.Navigation)
}
}
@Composable
fun GridIcon(iconResource: ImageVector) {
//TODO add your code here
}
Abagaro! Sui daje e vwuk oj isipw ud xda tgpuog, kyudaf ij dwboe jemiwpx. Sue tip anbnoifu whi vekpak om ocohs evnexe zni ahejh qayk bu ramu xwi yvor ptpebziwbu. Yi ojbafitinb pusw degbafuvg mupocg meogyl, elgfouqu hza vako aw wca cupt ju lku bacumiw focio etz keo qta duloqx. Hoem ur poqv lmog wia’do yevosoy wa xha picxuv ak zejahpd ytuf jub yqi nvpoiq.
Riysxuyezejiovc! Xei’be foinfaw e qoj ogeeb yaq no kik uoj dubfu memvibs ev ipunikqr at Mankens Fudcopi.
Key Points
Use Column with the verticalScroll modifier to make the content vertically if it doesn’t fit the screen.
Use Row with the horizontalScroll modifier to make the content scroll horizontally if it doesn’t fit the screen.
You can make your own composables scrollable by adding the verticalScroll or horizontalScroll modifiers.
Use scroll modifiers only for a fixed amount of content.
For dynamic and larger amounts of content, use the lazy counterparts of Row, Column and Grid instead.
The composable alternatives to RecyclerView are called LazyColumn and LazyRow for the vertical and horizontal scenarios, respectively.
You can group lists inside each other to make content scrollable in both directions.
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.