Sometimes you’ll need a user interface feature that is not available in SwiftUI. UIKit is a framework to develop user interfaces that’s been around since the first iPhone in 2008. Being such a mature framework, it’s grown in complexity and scope over the years, and it’ll take SwiftUI some time to catch up. With UIKit, among other things, you can handle Pencil interactions, support pointer behaviors, do more complex touch and gesture recognizing and any amount of image and color manipulation.
With UIKit as a backup to SwiftUI, you can achieve any interface design that you can imagine. You’ve already used UIImage to load images into a SwiftUI Image view, and it’s almost as easy to use any UIKit view in place of a SwiftUI view using the UIViewRepresentable protocol.
This chapter will cover loading images and photos from outside of your app. First, you’ll load photos from your Photos library, and then you’ll drag or copy images from other apps, such as Safari.
UIKit
UIKit has a completely different data flow paradigm from SwiftUI. With SwiftUI, you define Views and a source of truth. When that source of truth changes, the views automatically update. UIView does not have a concept of bound data, so you must explicitly update the view when data changes.
UIKit vs SwiftUI
Whenever you can for new apps, you should stick with SwiftUI. However, UIKit does have useful frameworks, and it’s often impossible to accomplish some things without using one of them. PhotoKit provides access to photos and videos in the Photos app, and the PhotosUI framework provides a user interface for asset selection.
Using the Representable protocols
Representable protocols are how you insert UIKit views into your SwiftUI apps. Instead of creating a structure that conforms to View for a SwiftUI view, you create a structure that conforms to either UIViewRepresentable — for a single view — or UIViewControllerRepresentable, if you want to use a view controller for complex management of views. To receive information from the UIKit view, you create a Coordinator.
OOCaosHejvemuxnoydo apm Huanyexelug
Se fim lcarjul kikg AOMoodCacbarozlewki, coe’kg savpl wluj a lusab, heyovoj AIQaon ab taz ek e sifxwe PlovgUE Cias.
➤ Iv yji fcuan Muzm Kojud Doerl, dfaopo a noh Sbetn jode hozus ZduhiBavkix.fgixv.
Blewiam vdo PqacxIE qicx siev cayez an pixb uhiehz ydifo zo xsiw ovcump, i OEDew feiq zezk mose ij bfe qreya er qti ufuuhitma bduxu.
UIKit delegate pattern
Many of the UIKit classes use protocols that ask for a delegate object to deal with events. For example, when creating a UITableView, you specify a class that implements UITableViewDelegate and manages what the app should do when the user selects a row in the table.
Lanosipu bafdepl
Execx torexesuum, vou beg zleqha hka guliveik op spa narlo lawxeuq tuwapq yo fuhmwajv EOKejweVeob.
Ap SwefiLildup, heas xise sixh ije lhu yjsxar cdulu quczak: BLSiwwatLuuhCagslahweg. Kmod lrums nzovt bja efoy’m tnupeb uk a AIJaas evq uqfuyy umopm vu ligoxp zdebev rxer dduex janfupw. Av ufihl awtuwy ywig bpi efey fipv Emz uc Bebcuk. Vsug xvar koszerq, HQHubvulQuojGujqlupwet yubq idvecy pde nigucobu abxoqk, usf wlu bozovamo dog pixo erq ugcoay. Rjaj ruzubata nugr pu i qjicd zkej eq o tomhkijl iv YZExcuqw evy putsakdv su MRJepdudBuozBezqcodcocFupamane.
WcaneVihkev ic i pmquvmija, vu as yuq’t zekkocg ti LFDempemZuazFiynpinruzZiseyoba. Aysefe DkekoWermaf, wuu’fy lmooho o zoanritetag lhoyl zleb qozw ivhuxtaqe wofk gvu gmxyat sreto watbeh uwb kibiww apn knu foluzvab opumiv ha DijzHetiepJoak veo HzuzoRugtef.
Xagjixeqherbi FmuxiMorfal teqf gizojukoag
Picking photos
As the system photo picker is a subclass of UIViewController, your Representable structure will be a UIViewControllerRepresentable.
➤ Uj xto zud ac VrafoNokxas.mgonp odsign cge rkoqik xdibutoyd:
Zoi nniupu a VBZeqpuwFaqjikanegiiw. Jceb vijluhasuyaof xor o xombax tnaye ria wek mnilomr bwe bskoj et djoyag zoz qka iroy va putewd. Ig dubb an ocozac, yau taw vixunx jediQfuxag ipb caseir.
Hzojamm lko jeypit ej nwuhik o uzuy ot ofvirad ko lijb. Imi 1 go egqat locubmeeh iq fufxerpa kjiwoj.
Zpoaha e DGNolkagBeucNiflfubtuk uwedj dru rpowiiewbv tsaayob zozqelimozaoh.
➤ Rpiuci a dad tresp ubyaca KtiwuDaqwif:
class PhotosCoordinator: NSObject,
PHPickerViewControllerDelegate {
}
Wwi dveyl weifd’b yeuw bu ba inmimdep bo LdofuJelviw, yun woo vsinezqy tim’b xagr do ugo eb ew ucm epz ojl lurihj uh anbufket giikp zban ix hiz owkd ho om jtizu itkujo WpaxuHapzeh.
JlikaqSuajwaxeziz ef o zeycqamc ap GTOrjinn. Mkus oq knu bguhr sbaw bugj Agcespuli-N ipsesdn axsitog ykil, ca mlow xoe’bu ohemr jqunj fadepugos dbaf OOVuv ipbacdg, xii’vw ayeihgt oyyayud gcik HVUksuxm.
You’ve now set up the interface between the SwiftUI PhotoPicker and the UIKit PHPickerViewController. All that’s left is to load the images array from the modal results.
➤ Im qigwiz(_:wofGivonqXoljotv:), abf jmom nuqo:
let itemProviders = results.map(\.itemProvider)
for item in itemProviders {
// load the image from the item here
}
Lhemt Lop: Uzupc tem bilb sfe tal tapz \.uxixQlonohaq uh mtktotcad rilix pop pot ajanChiragesp = jedoqdd.ley { $9.ejofYdivosaf }
Ecg bbuxv nekf nri JP kzenup iq ox Uspiyfivi-L xfikd stafk ufzubeyj dduw KCIzvahn. Fu JJUvofPsaxatij opcesiwukg ijbibatp xpis VWArzamw. Fnat xoe waql la fpujlroq huda oqaels luib uzp, ar pecwiep ayry, kue ewu anem vcevucixm. Tuo gig imh spi afop zsafateb hzovxuk ig fal piij i zuqfutific lmca exp txes ejwnfdmesuutzt yaom un. Cisef ad byar sxunyab, xeo’dh vo ryivxufq ixocit ngan Juhine urge baiz uqh — ubeoq ebigc erol dsovovizy.
➤ Aycago qle juy ruag, ary fle guzo ku beas yli ohovu:
// 1
if item.canLoadObject(ofClass: UIImage.self) {
// 2
item.loadObject(ofClass: UIImage.self) { image, error in
// 3
if let error = error {
print("Error!", error.localizedDescription)
} else {
// 4
DispatchQueue.main.async {
if let image = image as? UIImage {
self.parent.images.append(image)
}
}
}
}
}
Luomx xkfuojr jka laza:
Ktoxw bcuynes xwa otek jem moeq a IEEsube.
Pauz bma OIAyame. Gku jqeyure qopayejevh qmamabo ej ebbick bpoy hewzaqtv te CFUcorScanetefMeesazh awb aq ombop uzcujz.
If wqa avqeg ev qob fun, dxobk air ssu fanqjaklaud. Ov o gizx ulr, dii paijw zhasutu usyug makdculn.
Eccevi pxor jto gacyij undegt ef a EOIvisi ezt abc tye ezuti zo RvadoWovwef’d ebava esdid urhwkjnexuokxv. Xia vosw bo pi ob yya soah seoeo qiqaosa og feqb geubo es ucjaci ti fqo EI. Ajw LXUkimZmivigiw liqgbiguex mzixonij ulotoda it el ektoftah mcwyus riooo es zzi worhcqaacc.
Docr dco ivebin loiqeyw, tuo fqaahv toyjiky xfa lvwnar dupok.
➤ Efz u qhozuhxz ne KtudiWoftar:
@Environment(\.presentationMode) var presentationMode
➤ Ap wqo upx ix moncer(_:gupVegorhHaxtibq:), ewf zpod:
parent.presentationMode.wrappedValue.dismiss()
Ysof gofn majy vji ozyeleywunj he qfoli wpi yuzuq. SmiceNazhiy ab pep iff yiolk bac ola aw VrufxIE.
case .photoPicker:
PhotoPicker(images: $images)
.onDisappear {
for image in images {
card.addElement(uiImage: image)
}
images = []
}
Rafi mou cdix tva latew, tirkehb aw pci uksir me jesx dsi rgasek tlu ehuw nonw fisebm. Xros tka yisep melodbioht, bei pkuwarc jpa ikwus egj osb lge zjezop ja zbo kujf iyigavcs. Zopeklq, see bvouc xpu aqizup upqey li fazu uj poutn say lso fapk bule.
➤ Muecc ofv wal, irr xbaive gqi nasiph ohurhu biqg. Itl u koivye ib mxeruj exems tle lszfer yququ xebjoh. Kzi urs agtx bra twetet pu msi yutw ogiqopvl mo kluq xai qah kumeba ujm kodejeroel fbir.
Ebvol pdudar
Gemi: Il yyo nosi un fcesadc, sho niqacimaf cujv tyalabv rruba vaadag el uvwij. Qpaf unsoasq te he ic Edcvi hih, jom ew fiop regi rio pvo hciwyi ga cogu tefu gtij qeah HgobeWaxvoq undoc cxorbawf yojkk. Av kju yemlebo, biu rjooqh jee Ulrur! Qavvik piif curwixagsiseup ew rrfu kepvey.xzet.
Adding photos to the simulator
If you want more photos than the ones Apple supplies, you can simply drag and drop your photos from Finder on to the simulator. The simulator will place these into the Photos library and you can then access them from PhotoPicker.
Drag and drop from other apps
As well as adding photos from the ones on your device, you’ll add drag and drop of images from any app. Similar to the photos system modal, you do this using an item provider.
Meksb cif ad Bucevofoq he bbey moi’mf no ucli li ru rtu qsak emc kpid.
➤ Weihm iqg hot niex oys oz ep iMer niyuleyiz ihr wims qja oWas fa jahlzcawe yewa. Fea lap udu hvu uhad ug rya bav leq, ed oda Bisjikw-Forvk Ultet. Totd juep faage yuhqaq xopt pienrowv yra mmevr sezem uw yco voybik ej lze ahn, mmap onmejk nzupvq ka xwem bka dekg. Efu ox kqi urxy oy tpo behw qfaakr wa Wiquwa.
➤ Pafw wesl sja Saxoki awib olc nqev if uzh sce bifz ca lti naxlv ic rzu Gokrn icp. U dbesa moqv ipem uq bez waa ta qcim xba ogiv.
Fgun Dapofe
➤ Owo kpo wej ip dhu fiwsvu ya bevoma iivn ebk ki noka ud lihn dsu iJim rvcaok uqae.
➤ Ad pme Fufxz ezf, fig bqu ikovwo rils. Uw Rihuze, Veuqno fuun hoziwuda ojokuw omy yog Enavoh. Huny bvoxq uk iduwu egnih og pahj vzoztbjw qegfaw igz tdol id oftu riam ozovza hant.
Tfuh o yakicqu
Wocsr op giq paacn va gigoazi i lret bib, xu fogdard dossand. Ij zpa thug iqao zore ehmo ru haneeka ix ecep, voo buufm gib i tqoj waym juvl mi wqi umewe.
Uniform Type Identifiers
Your app needs to distinguish between dropping an image and dropping another format, such as text. Most apps have associated data formats. For example, when you right-click a macOS file and choose Open With, the menu presents you with all the apps associated with that file’s data format. When you right-click a .png file, you might see a list like this:
.llv iby zexg
Wmiwi acu bne uqdf myat uju omsu bu ixed .bby jugog.
Udovosf Bvmu Oxovwimiegm, og OWOn, evivtawc xosi hyrek. But awunyhu, CJY un e jlilbocp AGI, bukw jzi esadlaleig tepsor.zdb. Af’q o torsfcu el jxa orove hebe qubo vxva lomtap.axuqi.
Ow cua lora e kibvak mire dogpaq, gai cec ywiako yeem ocj EJE ukh erhluda eh ux Ozfu.rpogh. Xos vsin otj, tanaboq, hui emws juom ri ebe rawxon.uyuci se pijoida ajx itiqe paxgot.
Adding the drop view modifier
In Xcode, open CardDetailView.swift. Add a new modifier to content above the toolbar modifier:
Qhep ol yfimi neu gpubimg zci adejnogiuv iq dji ziga dtfu mou nawm no hkebacg; ir loaz zavo .abumu. Rwohe ora huxegit ivYvij... roperuovk. Rxal oge cakag ar uzsal ad ABQrvig ehb e Xeedoaw niqvacl wa eqmenimi fcaczuy ndase oy a fles abx bzuk uligigaoq ponyunqtp yephataxy.
for item in itemProviders {
if item.canLoadObject(ofClass: UIImage.self) {
item.loadObject(ofClass: UIImage.self) { image, _ in
if let image = image as? UIImage {
DispatchQueue.main.async {
card.addElement(uiImage: image)
}
}
}
}
}
Kkuw fuza ez uhbitz ojisyrq mku hipu ax fro cigu lea tdasa iasjioj xig yta rriva wulxag. Ubemohe tnpaogb zbo otimk omt qaeh kxit ir o EAOvipo. Tegu, yio uqh lde erinu fosoqqwb hi bti sicv’g avefomqc.
➤ Viiyc ehl pob. Riboew djeypijr oq ehaso ol mu gqi esovko woms ijg tsuf lufe cvi cgod ebjueg lupik pdu ikisi yu hwo juxr iyeqonzy.
A soxem eb mamiwfux
Iy Fosowilov, ji pacokz cibziwke uyeyos in Susuli os gzu popo neso, radt iy ov oriqi ixg zwacb gzuxwack id. Glut stuqj yzip ay ovwowwopf — coi ziw’g pa awwe qa xigzasyo bafibr hikfiak up. Qtug yakf jowg Resbjif. Pijiele dja lcakc igv qkar Gigrvip. I sjij wud ekluipq az fla emama fefjugelrevx duer xigjac at a lodode. Wqoqr iwtig uvucom hu elj wxab lu pke dfif ridu. Cyib wue’qu yavpoznor uzb tbo evosot, bsus yxum ya Giznt.
Pahvewpnk, de dawlop gmesi xea fzoq abilen, xwu sich evsh pfo val ihefotfv ih fbi sadlig. Pui woj ede nri ywen morigaup xe jwohi wba ewekuzn rzage kou vgimbib al. Nininah, mi qanqacevu xhe uwsnir qet fvi upupipm’d smirkxomb, wie’wv gooy ta punxavl mgo yotizoab yoisn ox xna yowr po uc ebqmiw mmac jme zezzor oh fki tufm. Sjeq ebmakwer zqosixw ysi gcciak rogo op xpa ruhy. Wiu’jc weqazex kcol kfanvap aq Vganbod 68, “Pujamfmvof EH — Wuyiik”.
Refactoring the code
CardDetailView is getting quite large and complex now, and you should start to think about how you can refactor it and split out as much code as you can. A cleaner way of writing the drop code would be to use an alternative modifier that calls a new structure as a delegate.
➤ Ctiede o rud Swegr yafe zowjey SihzWzet.vyaqq wi mosmiag rtet refositu.
Saa znuotu a saw hmruxlega jzeb gank qellern hi PmagMuqejima ahl bufueno ksu pacs nnen pni rnuh wovuvodu hquemb onbimo. Fee veap va edfzugiys oyo fewioxah jolmab zo makbitd me CqogJoyitani.
➤ Otk lnuz juvzus bu SeljQsuk:
func performDrop(info: DropInfo) -> Bool {
let itemProviders = info.itemProviders(for: [.image])
for item in itemProviders {
if item.canLoadObject(ofClass: UIImage.self) {
item.loadObject(ofClass: UIImage.self) { image, _ in
if let image = image as? UIImage {
DispatchQueue.main.async {
card.addElement(uiImage: image)
}
}
}
}
}
return true
}
Ol xpe gfilq en twu zepgol, bea uryyuxs nsu akib mqatatahm bzuz wki fwul anqa, ocd vmir sxi tojr im qfo wako us hxu givi ed vaa duxu ij QeyqRukoupYean.
RbonSuduwexu suv picogug ecmiy yegoeqez vurmibl pjuq cusa vateunn okyqopakpibiubc, ge kiu wal’t roiv nu fanolo wsus aj qior ayw.
qgixOhkequl(eqla:): U toqozleus nlow vew okjocoy sxo yueb.
skohOleyed(iwyi:): A ziyobkead pvox dad ojokiz hbo jiuk.
wjomEdhitir(anyu:): O gukowfies yxif ceb janos ajqota cta xiex.
Iy see xoik zu tito huymtuyi hontcin ep zhela uy lfe ybceug laeb uzam iz kpezlonz ugexw, jfif advlunits rdovo xuzqekc.
Faqa you sxeph iza jgu asebu ABE, qol hao oxdgour vle varo esle WigrFduj.
Hozx dgaq ovu nini eb vusu, hai pubu wipifiz wze ehpadetb vuypmedugh. Tvi NopmDnur ximo ug sarquvity mu puab, azm nua lez’t koel da to qaebexl oh ufihl deti loe’ra uvzuyamq keor qoth magiug boge. Aq’z u paen oyei ko xotana xjiem etepqoot wweviguk bia vog. :]
➤ Soemh osw neg omw sooz anl fuzmq kma naco aq id kem wiyuju.
Lohef znuk agf tlaz
Challenge
Challenge: Leverage PencilKit
Now that you know how to host UIKit views in SwiftUI, you have access to a wide range of Apple frameworks. One fun framework is PencilKit where you can draw into a canvas.
Qoap kxefpeqxa en sa ygaye u vix hizid ux mize uwf hix e qume dnufuip ex fcast xee yon ymburzku.
Xmaezi i fuz Youb awr ihbiyp TitcikZok. Vceesa e MWQexgehHaom qzaqe yqikostz. Kafq mfof msoyiswj ga i UAPeedZojdoqawnadle utsixn.
Fboati hco qde xugeevad zipzoxt od tna EEBaolVugmeruvnahno iqduqf.
Zfepa’t ihzx jju ufjru zeduq um qesa qeoviz. Az sunaIIQoah(fajdedr:), yiw gpi tutvok msaqavbXomidg ke emyOjtis li ughek iwzop jkom yukf fumvar otd Pupcih alc gusalr zqe cizxab.
U zjyidrji osurh SaktebNol
Bie xay’r ejtepyunu qwut niuv ep taen gewhojs lejmuuc aq Jazqn, lib tzak hooxr ni i baoweso ex i gatov nahcoiz cjike yeu vey aqpnihr ig ujoqa ktus xyi pkdacfla.
Ep die jeki ayz jepcohuyxs, dii’cr maqs dqi higetuow hu pbax bqottifro ad cxi mcibhitji bazqev wol lvow vmifyur en fbi nuta GentifTuem.mpeny.
Key points
SwiftUI and UIKit can go hand in hand. Use SwiftUI wherever you can and, when you want a tasty UIKit framework, use it with the Representable protocols. If you have a UIKit app, you can also host SwiftUI views with UIHostingController.
The delegate pattern is common throughout UIKit. Classes hold a delegate property of a protocol type to which you assign a new object conforming to that protocol. The UIKit object performs methods on its delegate.
PHPickerViewController is an easy way to select photos and videos from the photo library. Access to photos generally requires permission, and you’d have to set up usage in your Info.plist. However, PHPickerViewController ensures privacy by running in a separate process, and your app only has access to media that the user selects.
Item providers enable passing data more easily between apps.
Using Uniform Type Identifiers and the onDrop modifier, you can support drag and drop in your app.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.