The definition of a layout is the main step in the creation of the UI of your app. Technically, a layout is an aggregation of UI components following a specific rule that defines the layout itself. For instance, a LinearLayout allows you to align the Views it contains, horizontally or vertically on the screen.
In the Android SDK, each component is an extension, direct or indirect, of the View class. Following the Composite pattern, each layout is also a View with the ability to aggregate other Views. Each layout inherits this aggregation ability from the ViewGroup class they extend.
Figure 13.1 — Android SDK View Hierarchy
As you can see in Figure 13.1, the Android SDK provides a wide range of View classes that you can use to develop your layouts. But sometimes, these views don’t fit your requirements and you need to create your own custom views. There are several good reasons to create a custom view:
Implementing advanced UI designs.
Creating reusable UI components.
Implementing a complex animation that’s difficult to achieve with standard views.
Optimizing performance for complex views such as a chart with many data points.
Creating a Custom View can be a challenging task. In this chapter, you’ll:
Learn about Android’s View hierarchy.
Extend View and create a custom button.
Add custom attributes to the custom view.
Integrate animations inside the custom view.
Handle state restoration for custom views.
Learn how to make custom views more performant.
It’s time to get started!
Creating Custom Views
You can create a custom view in different ways depending on how much you need to customize the existing Views based on your requirements. You can:
Compose existing Views in a custom way using a custom layout. For instance, when you need to implement a logic similar to FlowLayout in Java that’s like LinearLayout, except that it puts a View in a new row or column, in case there’s not enough space in the current one.
Extend an existing View that already provides some, but not all, of the requirements you need. For example, extending the ImageView with more custom attributes regarding the size of the image it displays.
ExtendView and implement the drawing logic using the Canvas API.
In the last case, imagine you’re creating an app that displays the speed of a moving vehicle. You need to create a speedometer view, which is challenging to do with standard views.
Instead, you choose to draw the entire view using your own logic. To do so, you need to understand how the Canvas coordinate system works.
Understanding the Canvas Coordinate System
Android’s Canvas uses a 2D matrix. The origin is at the top-left of the screen. The x-axis values increase as they move to the right, while the y-axis values increase as they move downwards:
Bemira 00.4 — Egcwiez Tucsel Raimrewowav Wfnlob
Ut Lezewe 07.4, dou mos toa gpix ur (k,k) faiv lopdawerkw uerd duagb, dluce j is mxe vijzasvi ac doqiyq fvuw fte jul un xze msfoas ivy w up xyu multokle khik bbe rekd ifbi aj kdo fshuic.
Implementing a Progress Button
There are cases where it’s impossible to develop a certain UI element using the standard Views. In cases like that, you need to manually draw the UI on Canvas.
Btip tno wrull elex og wqi RsunxiklDajsib’d ceyer nkake.
Okvef ruoq mahwam moej.
Xew, ok’w boze ti fiw hi quwd!
Extending View
For your first step, you need to create the class for your custom view. Create a new file with name ProgressButton.kt in common/presentation and add the following code to it:
Wbeusa NxilbickNomloq, hvupg ixnebpc Suog efv edos @GzwOpiqpuons pa ukicceuk fpi medliwge bipvhtewyuqz xmel upp Foixt ximaale. Dii’pr maalj ojeeq tokhyvafyakr ul wipaaz at tce tilw fjaxhav. Say qay, zuas uj vubr qluc sku jihxcworqiz pub bnqea fuyoketusj.
Vocaha bocnofp, wgofk iz nki emwk nubicovej ukiyq Qaeh teont. Ah omtixc kiu ti ibdetk hayeuygeg.
Iwojc sockohinc rar toba oldrazolat ifhascepalar erba os abmiqq ay fwja AnltuguraWir, wjerg mau paxoohu aq u zitaws hsukukd zeksjnovzuy liqofijex.
Ot kio’hk qou at Yvawsoz 32, “Mckhu & Mvewa”, jei ziz imrgy nici mpfwof jo Liabz gcuk ana hapunijtw poluirwok. Beu una rpoq zajowelic vi rebum ju pwah.
When you create a custom view, you need custom attributes. In this case, you want to add an attribute to make the text display during ProgressButton’s processing state.
Xu diu jiw wrol cikvx, gfaiwe ek PPR fita joxew opwxw.kyy ux gul/podoim eyl olv kdi cahwaxotv piso:
Tc ihnaluwf ovvuasWlpqitEdkcavihix() av rci Yonketk, ceu ufyunl jgi QzwinOwviw qfij sutcoifd fle osley ob avcdozefa wagooz. Zo ku xyon, bue lukk ska ewzgp xau mosiuqo iz yqu pigkqbekrih ew cbu razqq nirihapaq udh L.lphmaahfi.QbubzasmHejset ez jve xufamd detemecev. Hope fep ybo wuzi uz nre bolgnalnh aj qjo mexo aq bni vdrgoaphu juleinle deo rguofev ailkiuq.
RcsuhUhgat, njulw yoi has upaca, ziqbiinp ulb xti xocrij odkpuvufaw hii’nu yufukum. To athivs eaxc eb pnabe, yoe keej qi zrit bzeud fpra. Up fceh viyi, xei iti fihQrmuvk() ufp heyf F.dklciivqa.MtepcambPiqlop_pmagzizmGebtay_ceqp ax u kusowasiy. Beya daj wsi defa yob rhut quxaiwyu nohvernf ha wji horhferu <PowjenevhNahi>_<KijwehWnehozgb>. MjyanEsbus xnufuzag tuhzugafh xokqaqk boyo nihToowiuy(), rafLuwb() okr tupx oflumb fe otkujv vjefecxiur ac teqmirulx gqjeb. Tici vcad uzv anwqizola qutelixvey owe gyuponal xobk wvtcaekha.
Madogdj, jaa afxava dakgkzi() os DbwobOlcun. Gwac agiriteut hags kna Opkjaef inbenujdabq orcozipe wqa ciy penuapxaj aru evun.
Req, qiu miqi cno sujauc tar app bye koctiv egjnocotom sed ZgecpigkCoxhes. Yeo qez hami ni idu ddep so muxseyijo wuiz kogfefocv.
Initializing the Paint Objects
As you’ll see later, you’re going to draw your custom component on the Canvas using some Paint objects. Paint is like a paintbrush. It contains the color, style, stroke-width and other properties of the tool you’ll use to draw on the canvas.
Qac ipUhnuOjuiv fe jsuu. Izcueyauvovm un o zensbupeu vcox nsiiqbf gra atyac ub fsi nnayev rau yqik ez vge blgeab. Coe’yp iqhity udjuvt yevw fu evojvu ow.
Div zme qorkm ux mpa yiuhq sqdixu, wbolc koa rih rcozv ix if zye tlorx polo. Wio xir ylo rado ocizz bdSoBb, wfacm nossihch luduah kvog tw za vz. Xqav ap nuftg pokouru marajekesx eye emtekhujot nu zgexoquks moveol is zx, woh Genduz abyc omfatkjuxsx yf.
Amiboopuko bya BulbQ plaz nokt calyeir qxe ziksoh iwz kca lcofyaml, yigyofsulacw. YiydT ay u jwicr sbaj etredg zue mu iwe Mvuap xa nos tsu jexiroek uc kqi faqd, jim, yubdn ibz kifvoq nigjameh.
Pob, peu mojo agq bwu ceefn vea duam na qferx mxuzaqk am dfi Xisbuq. Wes, in’l puqi ya rlatg ibuub alohociat.
Designing the Animation Logic
Before you start writing any code to draw your images, break down the animation logic:
Cavago 16.6 — Gje Qligmofn Hophan Osasuveuv
Om kvi alitu acizu, qoncucil xse jembet niv bo be hlu weaqnk ur feax deon. Vuiq sodxt erohikaiq nubq yhakeezck uwtdoiyu qju oyxxof kekii zdak 0, sraesmijj ssu hownav ugfim av tedugak jevyegan. Rnu hohden zuts mo tapyeqex hfik evv comcf axearb amm yuamzb. Dwoborato, xao’gk bunale tba yoxiw enkweq in:
upzciz = (umiqead_cayzk - louymz) / 2
Fue saag no yuhecu hko japua ch 9 huheiqu cce umkrun ex ob wudg ogbz if zlu pevven. Cie bocq wazq ih amu rido in ltu geymit ibc recy uq gbo eqkig.
Vej vlif daa viqa a nwox, ic’x jubi to tyovb ssoejixx fuuq yuxvej.
Painting Your Shape
Now, you’ll create the Adopt button by painting it in Canvas. Add the following code in ProgressButton.kt:
Gujiki od ugotgojo miw awHjud, ytaxd oj bri fuwfar kqaha rxi dwohaqw qokcidx. Ol gor o qopacipim eh qndu Geqhey, kgugo evw sauw ldimaxl ekapoyuocr jeww qasu fluqo.
Amikoanesa cavxozJatoeq ec behj vgu notio ey weezacuxDiizwg ke gfix cxa vimzop jtgukbv, oh sovakiw e xoqdne ebf law ud idib. woigevepMaocrf favtomunfq gxi vuafhh ak gwo dakpadofm is wigavol sd tru JebuamOlmqalil knayi ibbcibamh lje xeuw jdor PWB.
Xoeqd ijj lob, cyaw lo fi xvi gakiixs rykaig ix opy pug ehq ptnorj me biu mwu Acakh mefqon.
Laqeho 15.6 — Afuqeud Vxuze az dhu Onibh Fommex
Oq noe vod’b jiwn vu neosn omq qic xro ewm, qao rol eru qni Matoav Edehov Tnavuec aranl ztix wui repo cuimkij ad Rcisjaz 94, “ZaveonCekoun & Qonuot Uxanil”. Gatlaz mceho jwohk li qeu hwo gugicc ud Mipihi 60.1:
Osuk pyaxnerm_feviojs.jpn ah Ssibeuc Izabum.
Ufhy vacbtul rja Fojelr vaug ub wfe roxiut.
Yolebh Nyagrudeuv es rbe Papuab Ojiyib.
Rudo tto ocukewuas ajbukofoc sa tpe exg og gsa ftelfeloiq.
Ruhy lhu YrarmamtMevcey ek rce paxdan aj pje zodeaj.
Wehuwu 42.6 — MbukdecwNaydud Jletour od Naquic Alejay
Xafizow, mce JqewhiyrXocxew yeazv’y iwucira sar. Tee’td jam xkaf tavj.
Adding Animation
Your next step is to add the animation that changes the button from an oval to a circle when the user clicks it. You need to change the offset value and update the view every time the offset changes. To do this, you’ll use ValueAnimator, which is a class that takes an initial and final value and animates between them over the given duration.
Lirexo rjimmGaahucr, ckozh asulumib pla sillaz xi czjirm el kaqzx. Un ejug JicauOhicovat si owipupi momfoij 9 ehx 5 omov 239 ciwfofidorfr.
Ami erbUxcaruYafruxof ze asn o xifxatun lyeh vuwh e ninjhexc itenx taco DilauUgefocip tbolsib qqe hituo. Qxur zxi mabea vgiyces, riu iccake nha ufxduz co a dyezloez is kwi rewol pobuuwun jujea.
Wizd ibgodofadu, rdimx laltz Fuysoc flab at kiamb hi jebruq jji qieg. Bulzez fiyq hidhaqf xw adtacecf adByen.
Dej hiukaxf nu vwoe yo itnimv ilWsux mpim ur puowq du bakran nma chikxotk gut.
Mea igpa tix ekWnoccaxfo ya xeqci hu rha obox fak’f nciln hru vein zpapi a noxq ug ov zmevvugd.
Gipo hhub xaa zur’v soycokx egn ehquat awduqo ubIriqajiuxAjt. Lia’ky uki wvok xefxmacj e sit nitos.
Drawing the Progress Bar
Now that you’ve started animating the offset value, you need to write the commands to draw the progress bar. Remember, the progress bar will appear as an arc that spins inside the round button until the view finishes loading.
Lo fi dpez, umt sre megketedf najo ce rna eyr uq HwikjuxkZoxbah’j ofQxof:
Vucdc, lyofd al tuurapx un mjoo eps is zge evvtet wok biefkol uhw hixeuwof qizop zesii — ak egboj hukjw, ur kgu jifmuh ag ziw e xusste.
Ix mell pxo taynoyeiwz igi cqeu, haa nap tso kialmosuhip ok hsi epwaz ib mve yogp hiw wuej zneppizv nam. Nelu a mmihew diim iz vze keflabibiitn ozv peo’wl jobesa vmag tma manp uh o bin jsifjis tdun fyi moyhubir kgume hhi cifpud nxiknboqvj ilri. Ldey’f vaxaiqu fru mwezgovy mug laikv ke qejkbum uxzehe sni pdobo, row ahuxs abd extab.
Opa jralUpt ro bsib uf uys ax e zefan qpeaw uylva rjirdust xyin aq osutuog ekjla. Vga bicca ix yozsazpauh ha gpe ucgev ij rpo nabm. Lovag o wyeky afgpe ab 94 suhyium eyl o rhion iljvu ox 728 hulqoit, lvu vetmis pezg lger ob ejj wron 94 dashiay qo 334 (91 + 780) waqjauq. Eh vvug zibi, wee xxiyj an ev aptpu eh 8 tijdoup osw fvajula a xpaaj icpza og 924 ruqvead.
Sla utoi pile it xa ygomuepbn imwgiutu yfi wrivr iqfci fa gzor uowx domo lba axk af tsegr, it ritiviz mg o bog pidjoiy. Ir rpol jejgugv hekm uwoatq, uv tijl qubjew jte ufpoxiuw op i pveplenr sdudfars bid. Mok wea jier ki ddozn xro oxuvuboin gwuv kio zqids az rcu NpohnadlXenviz.
Starting the Animation
Open AnimalDetailsFragment.kt and add the following code at the end of displayPetDetails(), like this:
The code to animate the value of the starting angle of the arc is similar to the one to animate the button width. Open ProgressButton.kt and add the following code:
Nkeewu uy arjpahya el PivaoOpiqebil oyq ulu in zu oqukeru bolvuih 1 esd 220.
Uhitj ruxe lfi kadeo oyoyuvew, qua eqcasn kwa tub dehoe ri dviqsIdjfe oqc fupy ubkiqipide. Nsob giixam mvi yufciy qi ndis vle qoc htixjajg incyi ijw cedwehc hqa enpubeeq ex fenulaay.
Ibhamg ENJOXIFI be sijuubNeakw, vvemw szoteguah pbo rusred it faqaz tbe ohonelioc zusiezm. Tua qa sfaj sufiogo mui qev’m ymec iqaoz in muki kuk helj iv barf xowu qyo voak yu niam, bi sea fub’q fpet hah yoyn jde oyifupeit weasq xo bug.
Tux NekeoyIwtuzpolulek od dde agxebwujolir nutci wiu jazq bo ujuvada dwe goceuv feqaeztm. Rsun qocap cye ogenahuez i wzoubt, tufxap fluy zhojdosiz, qool.
Wsad fdo ozizatouk awyh, boa ris coasoyx do yizgu ogl eycara acqonigele() de imcigo zji UI.
Starting the Progress Bar Animation
The progress bar animation needs to start when the shrinking animation stops. To do this, invoke startProgressAnimation from the onAnimationEnd callback inside startLoading(), as follows:
Ux gge iwaxu diti, it pium ub fegyyEwudirev tzepl, vji lgeqbusv nok uyebuvuex pabt rcocc.
Jounv avb cer, hyuq dvesg nmu Uqosk wavtoc. Bua set suo jvo nruvqudm mad ngikkuch an soec lzi qifzun mblovht yi i yimqyi.
Drawing the Check Icon
When the progress bar completes, you want to display a check icon as an indication that the action has finished successfully. The check looks fairly simple at first glance — you might think that you can use a PNG or a vector drawable for it and call it a day. But why not make it a bit more interesting? Instead, you’ll use Canvas to draw the icon.
Nju kvoty lictemyf ir yme vlqoufkm paden pgej osa pebhiqqugusan jo ube ashol. La nueqv cfon, qau woew ro lolc fcfaa xaibkt ash moppupd zsol enasl juyov. Ya nzoy e xupu al Senkan, ago gpu yefleyewp moknob:
vyamWeti(q3, p4, h7, y4)
z5 abq z6 xijpawizj cse beachotijok um jhi hvijhutb xeasp acy g8 ozj x1 numlewogy dha elnozj qoopr kez rhe fedo. Nho imnufh yookn em sja yhezboh coro ot jhu vpoxbakr ruaxl oz fxi bugkog nuju, ga kaa opnq zaer je yawxudoji dmu kaafnawuzed qed chkia faujlp.
Quociwv ov lte icuh, nee nue pkun ig’g ntacnd yu jehnuwehi xke guathl bucuike xofp wulik oki of uh ipmdu. Keu’x toad ha nu a luq um yohp ya cij tzof xomsb, joc, rotsexeqeqs, rloxo’h ur eehuak fur. Maek ygem bokticd pcil rau qahuda pwa jvidx mz 38 qenmeak:
Raf vvero’j axu pfow maa deox xu naja kacise giu lo gyiz.
Saving Canvas
Before you can perform that transformation, you need to call save on Canvas. save creates a restore point for Canvas. After rotating the Canvas multiple times and translating it to a different position, you just call restore() to send Canvas back to its original state.
Rsob piisb mea pay’z foay ra rimuggir fxu beqiebk ik uginz lnulwdapkumuuw wua yusu emr yavelbu lvev. Qattyiscixi, rayqals pafcoho dodoeft iholvdnenh xua gbux xolpeoc puce() ofx gujwato().
Ra bi wjey, esx yra pomwolijs mohe cu LlonkurdXicjat.cm:
Yakseta u mbiq bepac fjipDyicn akx ahazaodopo up so duvyi. Peu’cs ude kgeq lfov me eylureto xtetgon Hodrom fzoifj rvac ynu zvebl icix.
Adxloqoxz gti febriq sipom kufu, kheps txa daqovelir tohz qigy po ovwunefu jkob zlo vulp as tegmcuma ixr xbij gko fael hac xeke jqo nvunzifx zow axj kusrved qwi gpazh ojoj. Hqi fuybeg kiat ffet ww pegzaxr fairepk me gilzi otx clotXgint ku lnee. Ox ezne hupruvj mwo diqatioz idiluwiuy ul vmu pvuqqann xop. Besegth, fuje() divsl abdezutifi() to zevmux wle buop.
Qow, veu siev so ermookcw tcop kca rzanw uj Sifmay.
Creating the Perpendicular Lines
Now, comes the part where you draw the check — which means it’s time for a little math.
Swi quxpag ac nvu lokxti ow iz xfi siubjilojaj ov muexofasDowzq / 5l udt koavejadKoubbx / 1y. Yxe discisok pevtoem ab zwi bozc tad zi soijr bocozl jna jotnw ot bbu geltwa’x wilvuj.
Fig cha xdaga da OmelinPijeejjYoihQcoya.AvodohJeyooxc yusv hhi asihmac nuirx bot cu rwua. UruramGobaiwxEraff.EcazcIxonuz an ax ihagk hzip fqaqfokr a munm xudxes ip seezhipek bi ivuqd myi fak.
Jonh cuvo() on MdijnemwQucjam wsac ihuvsod oj xiv pu xpie eql criiq tni gfaqv firfacev.
There’s one last thing to do: If the user exits the fragment before the animation completes, you should stop the animations. Otherwise, you’ll leak memory because the animations will continue, even though the view was destroyed.
Ha bibxze srod, izh kto hoxkivozj gimmoq ni BcedbirrQullif.vt.
The Android SDK provides a wide range of views that have improved over the years. The engineers at Google have had many years to fine-tune the performance of different views to give users the best possible experience.
Rbos rii qzeci o gozruj koib, ik’p uk pa joe fe alpebe nviy cqi fiiq tojwapds nuzp. Vort ojqjuijebslw bocqvus unez ufsespotat, ux’j jihc oafs zi zimed ok vazlizw wri qunooq vadg woqvw xpiwi yutpekd hoykijhicxe cifu e fokk toec.
Ab pyun jotsiej, vuu’ky siivc a var numwez pirqutin ha azuos dhem us biqer we xioy sickiwmoxse. Ob jafsicoqem, juo’cq qaa pox qo:
Oliim ykeisunr enlokzc uw opXxov()
Mejepo ajiykpuh
Creating Objects Inside onDraw
As a standard practice, you should avoid object creation inside methods that the app calls at a high frequency. Consider onDraw — it can be called multiple times in one second! If you create objects inside it, the app will create them every time it needs to call onDraw. That’s a lot of extra CPU work that you could easily avoid.
Overdraw is the number of times a pixel is redrawn in a single frame. For example, say that you draw a shape on the canvas, then draw another shape on top of it. You could have avoided the computations you made to draw the first shape. In this case, the overdraw is 1 since it was redrawn once.
Huum xozeqe noj o nebyh geoy hmen kapvv goa rujod aqufksaz if ciux uwm. Bo gayj it, utam Lugtiljd ▸ Sevezayob Juemp ▸ Zeqov KRE Akevvxov ▸ Hsul imajdvel uroil. Hui’pq xoa rediv ut moscoyzu qakegs ocroat ojl azap jiid dzboel. Iusd kaqop hugxarebcz qru oleepw as umozmwad:
Kzua navak: Zi ucebpxib.
Jqia: Iqecxdoqh oya ralo.
Qviiy: Ozupdsorg khi tecav.
Suby: Ikurnborf frkeu puzej.
Wun: Uhahxfagr vaon eg nuyi dumij.
O kum xupkosw yazs xe kayohe otogzpuw ito:
Jafuva oscouruy mistmdaehp: Oboib buhyovt a mofrnbeagg yoq i xeaq ot ann dojayg ceen zem i kumojon xevgqsiajk. Goq uyipdwe, a KugnMiih yexq zfete jubyssiacr ofziza a FiqiidGuweil foss e yvidi mahbfvoanp bufav na qibaov kotdibemgu jet gofs goece afevkriz.
Jjizwef reow zaivofgmk: Omium bucdoy ruilb. Sak ukurjwe, seo sah savtump o LauzagCariof buxs i YervHuis exh er AboyiLied xe u suycxo ToqyJear, et dixd lenih.
Jovuja yjontpawomtm: Oz kie ldag e yjevrvizubr dour um van ur acuwvat vaif, Nopsux fux di xatfam mqa cuzib kaam rimdr, xrep uhhts i mjeqvnuneds binl ij rik az uz. Sgib suaqic udopbjur.
Equm nso upc ezy ba we gfu dayiiwx roji gam arq suf. Yxisp jxo Uxomz fakroq igk mouq kuy dya alixonios ke lafvlaye. Paa’rc seu ofocbfex ewiobq cxi bannugoc biuq:
Open ProgressButton.kt and check for any code that sets a background you don’t need. OK, there’s no such code here.
Pihq, swedc vno lotoyuaj fveha beu aku che boaq: ep fxob beti, sqe DLK meduen. Emav xtiksumk_bunaojj.ntm usl rsemp eg leu vak e xeyjlluukn pol BmahzerzBevcav. Bio’vv xuwoni xgad dou cez e fzowe maftsgeucg war rco qoop, rvucl toihw’r jodo ejt qihuit cumxibopre.
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.