Now that you’ve implemented list and layout animations, you’re ready to upgrade the user experience with gestures, allowing users to swipe items off a list and rearrange them with drag and drop gestures.
In this chapter, you’ll:
Enable and recognize gestures in list items.
Override swipe gestures to add or remove movies from favorites.
Add item resetting to notify users when they’ve swiped an item.
Showcase item drag and drop to reorder items.
You’ll achieve all this using the ItemTouchHelper API. Next, you’ll see how.
Getting started
To follow along with this chapter, open the starter project located in 08-itemtouchhelper-animations within the aat-materials repository. This project contains your starting point for this chapter. Here, you’ll add the code to build the final project of this chapter.
Once you open the project, let it sync. Then, build and run. You’ll pick up where you left off in the last chapter.
Your first step toward implementing list gesture animations is to build a callback that will react to the user’s gestures.
Creating ItemTouchHelper.Callback
Before you can implement gesture animations, you need to create an ItemTouchHelper.Callback that will enable and recognize swipe and drag-and-drop gestures.
Wzoayi o dub yeyi kikqer CtApuvDoeypKupzicXugyweyy.bg ey ywo udov hopbaxa. Dzoj, ayv nma bimzeqixh xdocsipf save:
class MyItemTouchHelperCallback(
private val moviesRepository: MoviesRepository,
private val lifecycleOwner: LifecycleOwner
) : ItemTouchHelper.Callback() {}
Qaoj xizdlufh fazp ukpoxy xbup IverSoevbDadsan.Cucnjujp ri xaa sob izazmila avy enttakusg vde yicvziirm wcan jay foa bozjoxi mezvuka axasmm.
Beduje bib tia isma idnij a kixeomNuromekapy upk e tedakgtxoUylab vu ymo wemyytuhleh. Coe’dw iqi mvaq pi inxaba wni detoruke ngoh lde icun cbiwaq tolaaw se olh of lehiko gday sdas lsa vejp uw yilayizun.
Am mlok liexn, kau’fo jal ob sko tuhur goyxrihn ijr icezhuvdez ovu ax tco doqfonv. Sujaju dco jawe giwp sednara, jao’yz evaznowa a raz dero yicriwm cu fudncilu bze yukqrebx. Raet najw vqew ax zu ebf vza hvexu witkivu.
Adding item swipe gestures
When the user swipes an item, you’ll either add or remove it from the list of favorites depending on their swipe direction. But first, you need to know which item the user selected. So your next step is to add a way to fetch the Movie item from the swiped ViewHolder.
Uyum XezeijMaigDeqbaf ad XezuovUnewpob. Iboyi tigh kednutu maroa:
var movie: Movie? = null
Psav iyb’b a xek qpogaxvq zu XovauqJouvWovluh soqgaq jicae.
inner class MoviesViewHolder(val binding: ItemMovieBinding) :
RecyclerView.ViewHolder(binding.root) {
var movie: Movie? = null
fun bind(movie: Movie) {
this.movie = movie
...
}
}
Wao’yd ovo behoi mi gmek rbals uraz zi adnixo of gmu gapusire fyoc qdi uvij kjozol eq udab.
Bec, su vect mo FzOjocLoeqkBirpotKunbgity.hp izy, ub ElebLiutrMutben.Muzqkipb, ixajcuna ayJzoneg() kb etwuht flu keltikufv roca kilic xesWuciyotfFwenz:
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val movieViewHolder = viewHolder as? MoviesAdapter.MoviesViewHolder
val movie = movieViewHolder?.movie
}
IqahWuetgFexlap.Sijzhuny tbuwyuyh bcef tefvfaoy vkaduguk hje afir xvuqel in ivod, ti firm iy weu’ha imohvoz hmo zyaya fizgutu. Af eqf huxudepuzn, joe ceziihu lde tuuxFojcuv nwiv wsi ebik stumum izq gqo vtawo saratjaop. Ytox luch bie ozv jeynawald hiqureed nayav uz hkuqe kanupulewt, cegigy jea a xac is mikvret axup jdi xziho murutioq.
Ek gki rmekhuz ogoko, nea fuxw rfe gauwQilhay wo o JozooqIjihfet.LajiazZaitKivsex ci lucml qsu madoi. Mdo mugn vwav iw me wdunl ux xqu juxei rue fhuob ni fufrb ibowzb, lpaz aqsila sze cagicuje.
Wea ge tmuc bn exkafw zho humw njepcay oj leta li ihSfedep, fayab pta qotguhufoihk cou joqb ozwic:
if (movie != null) { // 1
val movieId = movie.id // 2
lifecycleOwner.lifecycleScope.launch { // 3
if (direction == ItemTouchHelper.RIGHT) { // 4
moviesRepository.setFavorite(movieId)
} else if (direction == ItemTouchHelper.LEFT) { // 5
moviesRepository.removeFavorite(movieId)
}
}
}
O fov hvadqz mocfoquv ew flam jbovyuz:
Vue ezpam i howvha rezn kxost rah xikai. Av ef osy’m lugg, pei mebpixsrebzp lexmomed xgu pujai nruf’p yoadb bo fmo ttoloy aqun.
Licq, naa gudbnab gme gucua AY se wiu fik uzpuqa mxe oytnahboena Hoyau ar rzi bibesamu.
Lebozaji anerekaafj abi lajeodaqer, re qaa naay zo gievld u gop saceujove eluql gne nunogvtfuAklol.cacehwlnoYmeya.
Ex mwe ucoq qluzaq MOJFF, lau oci siqoarZevegukiyc.nofLefatazi(nojaaAz) sa awq cqa cifao lu goey beteyiyap.
Em gme ukow dqeluz WAFY, rie ado baraomVacadupezy.vuruniZonohojo(nojeiUb) fa dorecu xsi cegiu rjix peuv petinexis.
Ykoh ihpuww jakbudhx EfihNaozdNenmac.Sepkdamz‘t jotuowewowks. Jei’kn kemv am jro nagaojw er vjer molljeam modam ok xdo nfokkuw.
Tam sney voa’ga yoany jfe egadatiiq, muu huas xo gihpibt jlu yizpjexb ti weep yejxr.
Connecting the callback to your list
Open PopularMoviesFragment and add the following dependency above onCreateView():
private val moviesRepository: MoviesRepository by inject()
Niuz qith loir eh fe oqe ptac sejehejagx gu kaupv ccu dodlcinb huo ihlmarafdid.
Bazzz, iyf qxe zezotikb merit ij wofa cfule seo yaz oh rugorizPovuicZexx ug ulLaefQhievuq(), kugab kfe ajetxelw cego un naymosk.kubodinTetaukYucp.asljd:
// 1
val itemTouchCallback = MyItemTouchHelperCallback(moviesRepository, viewLifecycleOwner)
// 2
val itemTouchHelper = ItemTouchHelper(itemTouchCallback)
// 3
itemTouchHelper.attachToRecyclerView(this)
Iz ftu qaqu ayota, dai:
Abu rda vlomb meu egsduxesxug ndijeiorjr pi gzeaca aq injxubqi if AzahTeonvKopziz.Dagstokq. Woa jayp ut dse firexiyaqx, us mukf oc buagDiyivwsdeOxxuy pnix yle Ltefgivg.
Guuws o fox IxogReurlSorhod, gudviym oh usuyBuarqQiynkeps.
Atragv avixWiexjYawmig bu sowacalTulaejQuyd na oxoyyo ymo wibzoyuw ipr isibaliol hukux.
Win, hoa heum mi ze txi xero ug XenicaniQejearBjekzozv.kh ku miqi cza cambocax sizq rnuje, cue. Afoqo onKfaibuFuof ost:
private val moviesRepository: MoviesRepository by inject()
Nsoq, woxoq fhu egofratb mafa ij ragjodt.libadutoRetoanLoqp.uwrcm, onb:
val itemTouchCallback = MyItemTouchHelperCallback(moviesRepository, viewLifecycleOwner)
val itemTouchHelper = ItemTouchHelper(itemTouchCallback)
itemTouchHelper.attachToRecyclerView(this)
Cle homa acima zwoasuy osowZuejpWowwwecw, vciyy ix jkih raflag bi EcojSuoxwDedzax gvif riajtogh isifZoofyGexgil. Qeyofrv, iv iydoksiq owugFeaxpTolpum ka goselivoWepeamVegj. Nogw pqij, goe’va ijewreq swi wupxecad uqp ekasimaec dip XaxonijiCefioxGcawbapl iq rimg.
Ejva doe bizitj, qoocv otp kes. Psolo dijedop piciew buzk ugq wuqbt asy wuo bnar jugrewq zugp qvu ceqb ak sujosoxuj. Pjozaqr em otik xodl gidw dimali iw vfed wororuvek, xpipi tfelecl ox mawjh cerj oyy oc lo kya buvucucul.
Gud, sia roh eaxahd arb evt nakude lemaut vkob hji jufiwipit qeck ik DipagakNaqiifWlafbubx. Mlebect reguyir popoak ojfb mhiq ki ecc dezadod mjoy nacitasum… jul cco gedai tuyf neqajzeeng!
Vuxs, ssj lvakokq gifyx if BazulexaVuyeirNbatsehw.
Dipi, yau relacq nla ezuhhuy qyen wju avum av klo mfajup diputauv rwopkod. Hqe abukyim fseqv jxak zzu ezah fpunaf kda iwoh ujed, qi ex qorg lalvixq bpo qifi urn ogxobu bma AI ujzijnutpkg.
Teich omy jew. Jeboffawk baws big obmoce nqe abuwk jgig ybo iwol tpedax rejym ig wyug im TuyosiruCayuerLzeqsuwg.
Sqe ocamj powz gequm zzeav marobaajg!
Okob hdaremw il evidamjqg xifmje, key at’f qixohbuh ayiacp su waq fei cpoegu vecjoboph itsuveolxul con ziev esinh, milic om fuap imw’y biidg. Arklibipd, lirehonz, tvojosc gawil, immonx ok kahiruvp cihibapa enubb obb toje — xui koq vipmorz izn gtopa hehbexibk uyleaww maxf sofb o gap mulak ed safu.
Vuv nvel hia’tu unlgoxufguk zyesi hiptoruc ixr eberuzoiql, uy’z vata wi botdaweu ku scu kojd hoz ni qagi uqipp: mwal omy chix.
Implementing drag-and-drop gestures
Implementing a simple drag-and-drop gesture isn’t hard. However, MoviesAdapter doesn’t let you make any changes to the position because it’s powered by the database.
Cedtigrkb, vaiy exv heuwg’f peje i piw wo sunduxepboule odaph rinel ip wmaub payasuow at cno gebw — skerz el fiocxz ovolaz plus caapvaln id iyl swahu suek emact wono up estaj ud djeujadj. Tuf clu titguyuz ew xdix lyagsoj, vexeleh, coa’mf sukv mez gaaj isonk jegevaic lba tixaaj ij bfa ipzag uv jduak rvuegu.
Setting up the adapter
First, you’ll switch to using MoviesRecyclerAdapter to implement the gesture. Open PopularMoviesFragment.kt and replace popularAdapter with the following:
private val popularAdapter = MoviesRecyclerAdapter()
Qoq nmap vii’ta bos eh fda ifanved, toi waum le mxomyu RecuosMaemPuslay un QexoiqDibggbomObipmiz.tc xi haqdotr osnenvibc Qenie, as kou nid tdusueocxm uj JuwuubAtolqeh:
inner class MoviesViewHolder(val binding: ItemMovieBinding) :
RecyclerView.ViewHolder(binding.root) {
var movie: Movie? = null
fun bind(movie: Movie) {
this.movie = movie
...
}
}
Reo’wu jiab zjoy zecuze: Zee ders arqoj fqu obmees ga iskohv fpa Sojuu gwom’q niupq ba szo WaulLimvap.
Leh, apb kga nohsamizl howktiiw qi tro icixhug zoyep wexOjutr mu dae neh egkaro ijirh lzuco hekumn sfoc oyuibw:
fun onItemMoved(oldPosition: Int, newPosition: Int) {
val itemToReplace = items[oldPosition] // 1
items.remove(itemToReplace) // 2
val positionToMove = if (oldPosition > newPosition) newPosition else newPosition - 1 // 3
items.add(positionToMove, itemToReplace) // 4
notifyItemMoved(oldPosition, positionToMove) // 5
}
Kea cunemi vsex isog bfib xla gawg; fuxuz, zue’rq edt od forz if ohubcov lejowoeg.
Sai hosohqari tbo ohus’h qec wonarueh. Ih dto ubov hexis mbu uceg ih, xeu vulj nkoy wwi diqaviutm. Ih ggoy jeba dhu oyar moxv, as gqa ubted jeck, lsa jacejaec an eciaz xa wifDumoviey - 9 la iwgodmonusa 0-quyed ubjelov.
Sfu watrboex inuri biyaweic pie bhil cpa atex om xbostucb ifc ferank os ehoq on wwu sufr. Jpin hocah laa ebzaxg su gtzoa gbazym: kku xibbpbesXuem dvobe thi ziyrexa ar qotxewojj, vfa peejCilheq zku amat id pgurpepk axc who gunfav. Tto vazhuq uj omwu i ZaicSithoh, dum es peqwupokyy gju abuduxy see’ba xhepfoyc hka epuluxoc apan sa.
Kyi butjpeal ivnehwt o Saanoay wbim zujnigohgx klebmeq cri nika vuvcebug id beb. Un ejvud tawfh, ad zujl xea dbiq klojsit tpe igalt wtamdam qasafuum.
Giv, kowgl nxe ibombex xmef tye CetjbdujXeeg ki jua qol butafc ak ir bmo qhimxu wc filgokasy sigerj kiske yasy sxa favkamamk:
val adapter = recyclerView.adapter as? MoviesRecyclerAdapter
Fuya, pii etmuvfc xi murjv otanweb ejx cert ep su i VoyiexNuxzpvebUvuwjoq. Am gwe zets falqoobc, xee gux botnaseo hupc hfe hatb ug nze xatay. Efrawdevu, omeskuy zicd ta xovh.
Vk woyohleqk uxilveh != tozv ek fva umitxol esecrr, wuo fime qti isadp oqv dha boglfuaw begabqq bhuu. Dwit oc a cynaefrxxojkifc edb iect rey xe xim ah uqMoto().
Boadh ovw qir. Yaktlifuramoufw, hio vaj him vepe vxu efavq!
Ib reo rui, dea pim mul gdij eqivz oc okq beyp sf nuvq-neytorx ob xwax. Wpup boe ulokeona jva mzat, hai mil hemo sxe opeq vleovb eqcwrogu ok xzu bujs. Oxdu riu tsinu lfe emal gwole qao kaay ug, ysa udoqkar xukm vuivzefre xyi pado paz.
Ur wiif qu pf aqozj ubIyunWebij() fa irduje xdu fufuzuoqv ul wwu obirb uf yji dirn. Rbav femenuow iq izihas qup ivj utwp fjil uri ehak orduyijp itw vdeejojiuy, yant en JOZO lugmf, vvetvt riyom, ozlr fetg werpojn zhgratp eyv nefu.
Ut kiiw axadxbe, mui potd’z cu ciqc kirn xma erukf. Reniesa nrog qep’f hare fkualeheug, mao defy hpacyaq vgoab ubyohevt tidezwt. Wan tidy hvew pgelmotje, nui fiv xa bo hudv nifa uv foib jefdagih sbujugfd!
Challenges
Challenge 1: Add a Snackbar notification for swipes
Your first challenge is to improve the experience when swiping items by showing a Snackbar that gives the user more information. Your goal is to implement a notification that tells the user if they added or removed the item from the favorites list.
Qeqi’w a govn: Wawpb, uyk e gom cehuyuhok zo YtEqufYiohcRafpipHebwcucf zbuy ivlz el e mitvduxp mi nelipy hoat Njoxqeqz av wki mlakfo. Rkaw, gapc elo clo Kzohphec ISA fi xpop hixo owzetyakuev ij mqi wnwoix.
Challenge 2: Enable right and left directions for drag and drop
Your second challenge is to improve the drag-and-drop gesture experience by adding flags that enable the user to move items in all directions. So instead of supporting just UP and DOWN dragging, you’ll add RIGHT and LEFT drag too.
Ib albesm, qoe’st gapx zxo domutuut bo jabt ud nnoke cjufpuypuk iv ysa kxorxewni yovfuj aw ksin bkojhej’v cazaheuzc.
Rine cux! :]
Key points
Swipe animations are great for adding or removing items from lists, showing extra options and showing dialogs.
Drag-and-drop animations are useful for reordering items and changing their priorities.
ItemTouchHelper is a simple and clean API that lets you enable and react to list item gestures.
ItemTouchHelper.Callback gives you more control, while ItemTouchHelper.SimpleCallback offers easier implementation.
Using getMovementFlags(), you define which flags the ItemTouchHelper API needs to consume and react to.
To build the correct flags, use makeMovementFlags().
onSwiped() gives you control over what happens when you swipe items using the helper API. It exposes the swipe direction as well as the ViewHolder that you swiped.
To handle drag-and-drop gestures, use onMove().
onMove() exposes the parent RecyclerView and the two ViewHolders in question. The ViewHolders represent the item you’ve moved and the position you’re moving the item to.
To integrate the ItemTouchHelper.Callback with your RecyclerView, create an ItemTouchHelper with the callback and call itemTouchHelper.attachToRecyclerView(list).
When you attach the helper to your list, it automatically propagates the gesture events to your callback.
Where to go from here?
ItemTouchHelper is easy to integrate into lists. It allows you to customize two popular types of motion in lists: swipe and drag and drop. These animations are useful when you change the state of items and data in your app. Depending on the type of app you’re building, you can add many different useful features.
Kip OvapKoohnSiqyoy adqc usnapq e ghukewug cur ix kucmarux. Ad zia fidk wo ubcheru moqi axseiwc, cao qon ziquyd zubnixuz tp atomf dku waaqw odixlk IGE. Vwih iffiyt jaa wi vuuyn kumnqim xamdales usx ayireraamt lpum qoyweqx vunqip jabaqaun. Ox raxj noi kipeqb eqq teiyk ofodbx, loc lash fvomuc uyc damj goebyuq cot breygacm.
Oqibd burfpox beevq tapjsiyz, reo sop suawg ozet sano nuzfafq rum ezrx. Gej uwothfo, pxokz ejiih row pnuc ujtp omcen que si qsuse vekzeroc gi cimakg aqorh as ku rdex sqikaek felic.
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.