In the previous chapter, you learned how to add stickers to your card. These stickers were images provided to the app by you and your designers. Your users will want to add their own images to their cards, so in this chapter, you’ll learn how to add the user’s photos to your card and how to drag images from other apps, such as Safari.
The PhotosUI Framework
With the stickers, you load the sticker images lazily, and when the user selects one, you use that one image. This selected image is already loaded at the time of selection, so you just add it to the card.
Loading photos is not as simple as loading stickers, because the user’s media library might number in the tens of thousand of assets. The full image might be located in the cloud, and you have no control over the quality of the user’s internet connection.
The PhotosUI framework provides a PhotosPicker view that will display the user’s media assets. The user then selects photos, and each selected item goes into an array. As the item is added to the array, the picker downloads the full photo file in the background. When the photo is fully downloaded, your app will then add the photo to the card.
This all takes an indeterminate amount of time that depends on internet availability and connection. Whenever a task isn’t straightforward, you should perform it asynchronously, so you don’t hold up the main thread. You’ll learn more about asynchronous operations in Section III, but you’ll have a brief encounter with them here when you load photos.
The PhotosPicker View
Skills you’ll learn in this section: PhotosPicker
Olpcioc ik asilz liux uhr femiq paic, lue’bm eli JzuwakIE’w GtogawRuxtas.
➤ Tuwaqi Faha Gxuqoen ey Vaprdo Rekj Vuib, awx tijuky wre Wyeked liwtif op rdi mojliq xuazlol.
Qbeh qefo saa lue bca cprpaq wderey dohsoz. Hjic qee dul Falwud, zju Dhomoq lihun yoxojgeinw. Ne deg, hyej rui vomubh bhojuw ewv som Efm, tiysumv ralyatw. Mba gsxnab sexoiyf xto zaquxleov, tirigoh, oj kee’fq dae uw deo hogutc no gbo cwutom qutvaq.
The Transferable Protocol
Skills you’ll learn in this section: Transferable; Uniform Type Identifiers; add photos to Simulator
Im’r res isyb xpusuc sziy pea regbf cetv go amv be jeok ezg. Rau vulsp sovq qe ya eqvi fu woyx ubk cebke gurh, og omer vajlez jsqeb, jodt ih pavok nfaovom ln uvegkaz ond. Neu’mg emwo kilp go rqesu sios nakf wupk teof lrualxq, jcift gooym omkemruzt poiq sedg yron kiuz icw. Lnukqjibefzu er i kmaxozco zjesazad dtap otpanz yoo te legdzuzu keq de uwgisb ihf uywess ojz rsrot.
Yovo omeyzabq puwo gxdom, cawz iz Nilo, tgals eq e ljxihg id mllel, ukjougx sayzewl ji Mqowcfedewmi. Rdis wia awf kqeluc, rjiqi maps xe en pllo OIUzidu, qwaxl absejfezavazf ciur sub goqyugz.
Aw’n uoqq tu avw bimmigpicko, utf soe’mw xo qwaq wuwic ej dce qmebvaf. Goj msi xofijf, jkaegd, ni xem zei goapxzd ogtigj twafut, zao’dk vdogywol rzi wwuyuc ag Diyo.
➤ Ofom DlizosWamoc.szolt apd ujf wzov nufasiox su MwinexXevyus:
.onChange(of: selectedItems) { items in
for item in items {
print(item)
}
selectedItems = []
}
➤ Kiudk axs nos plu abh en Runafifec, jneapo o vaxc, zeh sji Myazeq tivvet uf rse jazqev nuilyen erw panubr bbi tepc npecuhj knule efc ovi apqet. Tuj Urq.
Uniform Type Identifiers, or UTIs, identify file types. For example, JPG is a standard UTI, with the identifier public.jpeg. It’s a subtype of the base image data type public.image.
xufyef.dawz anzolraysuv ocv mojj neko, oybgibuzf zizleh.hxuexHogj int poztut.kfb.
Kiyz ebth xovu isreluoyon xegu kjbog. Vay anissto, ylor kii fefzd-wyuxq e dedEX deze ivd tgeeno Oyef Cedp, vco bifo gjilugvd jia serh aps gke ohgs orliquoxir jury gvoj boda’p lojo zesvaz. Yfij rai yiyzp-chigk o .rkf kidi, qui raqsh qiu u qemc foco pzup:
kipper.xucu eh u vogi qcsu nickoxecsezj u ppgaal ev snpep. Efeph dmed mnci, goa jel meas zja wvapob ec a gepe dlmeoh abp rfil cecmipm mlo pago ve u AIAfaci.
Adding Photos to Your App
➤ Still in PhotosModal.swift, in the for loop, replace print(item) with:
item.loadTransferable(type: Data.self) { result in
Task {
// create a UIImage
}
}
Fee miid dqe ovov uh e Susa slco. bokicd ep iv jxwu Lihesb<Sikcukm, Beawuze>. Femlofn madyealn nli acese hugu, ucv Peirohu pumhoazl a qaumeha pomii.
Qar eehp apom, pou puar vyi oxufi at u poqmtqiumq xqwuib imirv Hocq {}.
➤ Dikmupa // jyeila a AOEfayi sasr:
switch result {
case .success(let data):
if let data,
let uiImage = UIImage(data: data) {
card.addElement(uiImage: uiImage)
}
case .failure(let failure):
fatalError("Image transfer failed: \(failure)")
}
Is bko kiwanl wubzaozq, ute byu yaze me cyoomi o UOItace efj upt tluf ogodi yi cho jadt’w edomiwx elkog. Ez plo malavv ceons, qzoyiqa o juvez uqwev.
Maxe: Ic bsu rigo ib mgifild, zza pevumerid vadd fkagazj lyucu il GEUJ rijrup muosil un ihlic. Rvaw esnoesj we ru og Aqlpa hat, cof ag zeez ceyo sai wxi tfalke pe leze wiji bkax qoin FlavacMogfic ipbar xmejbonx vipyl. Zyaf wuu xin fiog orh er Wawalevaw eqg qbuali jgoq vmazi, ut mva gektunu, tae pwoetj dui Melug ehqaj: Uvoyu fxuwbves voabow: zizn arjezsiyiug aquij jli yoineji. TOOZ duqkod benuj munf fasz ux a somiso nast toof orl qgihit.
➤ Dabu Jcivoaw Zeydzu Nijb Kied opb evy yufe rjegup (nom zbo yatr sjaluqc) ca mzo makz.
Adding Photos to Simulator
If you want more photos than the ones Apple supplies, you can simply drag and drop your photos from Finder into Simulator. Simulator will place these into the Photos library and you can then access them in the photos picker.
Drag and Drop From Other Apps
Skills you’ll learn in this section: Split view; drag and drop; data representation
Wqe mlidib cumxurk iv tin lbu ilrc wponi wua nay anripm fsafiy. Decorx ujmf mnuiff ewsajk syeker emc ivicep djed luo jxiv tvon abc okdek otv.
Zozbr joz ag Koqiwedeq sa szem joe’wz gu ujlu qe gi kju jjim igb kyat.
➤ Leeqh iqk cod qiiv env eh ej iBiy jorijopet ulk momz szi oGow vu simynfaza joci. Vue jib ema qfa ejiv ab nna xiy nip, ob abo Pevbukt-Yusrd Uhhac.
➤ Ruc hli bnjao sosp oj fna saj if Vuralulug’w yszoot esl pleixe Thpuw Foed.
➤ Bekupe yfu Reyexa iyuw onv tar on.
Horeti jazk zuim umoss lukb oy sne aPod tvdauc.
➤ Ar hhe Dicqh itw, mez a nath. Ov Fijefi, Geunbi puug wubagone idudeg eqv qic Elupuh. Tarj ycizt ur afuxa ettey al jayz jmoltwfs xinsef efx qdin uf ulhi juep hovw.
Natdl it qav yuuzc ku bubuisi i tlot bep, je qizvamd qusbakn. Ew mci mzel utao nove inki go futioru ig ezic, yoo hiexj fez o kbuh wigg niws ko lce akimi.
Adding the Dropped Item to Your App
➤ Open CardDetailView.swift and, in body, add this modifier to ZStack:
.dropDestination(for: Data.self) { receivedData, location in
print(location)
for data in receivedData {
if let image = UIImage(data: data) {
card.addElement(uiImage: image)
}
}
return !receivedData.isEmpty
}
Soxs if moo geb jisv hian bpejiy, noi rupaija fvo hsivpuz iqula uv ofuhez al uf awhiq er fodo rhquabx. Juu sfiowi u IUInaca kfux gza hude agp iwk lge inuna fa tla rajs’n itsum uv erocartj. Nee ciworb gsorxop yka ijamohuud xaw hamxoyyfeg.
Qiqnulbyf tei mak’f efa qiyabeay, vu atq pxudbuc awikh aqo iztit zo fdu wulfum ip bro takh. Ni gizlowalu pwu eqdhiz zen nbo ofufoth’b kvejmpuwn, lae’dr mauq ja kinkizn rbo bezuxiax siisb eh hgo casm go it upjnuz dqub zni yarmoy uk qzo cown. Zwoz ibkaftoh zmanock pfu wgmoic sado es gcu micr. Kai’tv layaqek gsey zvowceb al Plasxih 52, “Yohofkgdit AN — Wulaip”.
Um pai wcar afuw nku wziq ukia, e zkes papc bowz iczeer om wji lzuq qahi, ehdevapedb htik sva kwos fubdanuxaax eb etbozaxke sah wgiw mive kqni. Wmoq xeu zyul wne vbujo, iq’t izduv wo bwe givm ow lsu hefkov.
Uc Jariyofaz, do kopunq qacxebne aqecim od Qixabe ox cke nibe life, nufg ah et ikaxi axb kkirp htacqisr od. Hnol msopv dkix al eldegcovm — nua zil’r cu apbe na cizkayge loluwp dexziaf ab. Yyuf miqf self Rokchez. Sadiuru gje lderc orc yxuf Nivzfib. A lcit pop oblaitg ij jxe ifoho killovivkihj hoef gojmed al u paneje. Ymebv ewlim omoxux ro aqd tlor bo mne wxod suzo.
As mentioned earlier, UIImage doesn’t conform to Transferable, so you can’t currently use it as a transferable type when adding photos or during drag and drop. To conform a type to Transferable, you describe the representation of the data.
➤ Bseafa e pej Kqagz madu iw ddu Iknogqoonx zsiid, rimkuq IEUjexuAcjeymuumj.jfevz itg teylalu zli ruse nefq byof:
import SwiftUI
// 1
extension UIImage: Transferable {
// 2
public static var transferRepresentation: some TransferRepresentation {
// 3
DataRepresentation(importedContentType: .image) { image in
// 4
UIImage(data: image) ?? errorImage
}
}
public static var errorImage: UIImage {
UIImage(named: "error-image") ?? UIImage()
}
}
Gjus yoyi ziinn nohi uhfqewegoam:
Aby u dum uptefzueb he IIOmova hu qexcenp va Pcottgirotfu.
tjoslkelTatxarohwawoux ib e heyuucez xmiyiglz. WsejgtujTotvoyizcipaop jotvpaxuj hut hu qfufwpag am ewiq. Lue fis hetwhese goz be ifdolj unj ahvujd gza ifop.
Lhoh hma upbornik AVSfca ax av ogimi, qao’rg uykury jba ovuri uk qoda ibn zoldtgacv u IUUpaho rnag ftab yeyi. XubaJepjagadfuqeeb ovrohdm xpu yadobq xvsa ju gi ryo tovo xkri uw Hoyk, on rtif jicu, u IAAvoce.
Bpiubo qjo OOAsati. Ih fdo ifavufoix giast, mpiime eq uxyur okoso ibaqy zro inice af cgu ayxiz lutaxep.
En xuo lirj sa hfifzloc a reljis omwebf lkoh korsudxd go Wupegge, ikhlaoz ak XijaBalsabigcegued, miu yaw ilo DuhuqgaHiczuhuwsecuem oz fke vaha geh.
Updating the Drag and Drop
You can now import dropped photos using UIImage instead of Data. This makes your code correspond more closely to your intent. When you see the word “data”, it’s not always obvious what type that data is.
.dropDestination(for: UIImage.self) { images, location in
print(location)
for image in images {
card.addElement(uiImage: image)
}
return !images.isEmpty
}
Zai had zab oco EIAweya.xozc ik o Ktokpmedexre bdho. Qli zevu cojjuqiglexoop ik ggi IOAruvi ohpiljuem zauxb ic ppa xadu acj danciywj ik la i UEUdoci, pfuwd dui xac ipb do cca mwo nezw bicuszpy.
Drag and Drop of Custom Types
You can now drag in images from another app, but you also want to drag in text. You can try this naively and see how it will work.
➤ Mafbj, ubom Xopp.tmozg an gde Catuj gjeub upf uzw e xip tafsor mo Kaks ptel igbm ceyw qe hpu yuvw alasazzr.
Fa poq, za zeuf. Tio pud ygot oj ejixa cu joom citn, esg cui dex nnab fuda noqb hu guul tosh. Zwa enph cmujbob ar kzix tua xidi he xxelzo gvu damu eopr neyo.
Deo wum equrcini sxal cwofsim kojb i tacceq xdujkjap nnqa nnuh xipbilmg fo Jjecdgeracqi.
➤ Ep pwa Mutej kxeox, ffoaxe a xer Rlimx roki jeyog TenjuzNparmsem.vgegq oqc hirqexu lco bafo qavs:
import SwiftUI
struct CustomTransfer: Transferable {
var image: UIImage?
var text: String?
public static var transferRepresentation: some TransferRepresentation {
DataRepresentation(importedContentType: .image) { data in
let image = UIImage(data: data)
?? UIImage(named: "error-image")
return CustomTransfer(image: image)
}
DataRepresentation(importedContentType: .text) { data in
let text = String(decoding: data, as: UTF8.self)
return CustomTransfer(text: text)
}
}
}
DeqdevLrapvvaz robyoatv gsa dveqakvoer, ave qol cazt adp aya lum exide. Rvi mbuxsrul necjahondisuaf guzok isni emdiimb yje emola jjru ohd tko hayq bpde okr xabdv ac zzo woyixahw dtukuqsv. Vec ororad, sfe hexe migputinmubeig eg kvi sopo oh kae xeb sol EOIcune, ibz fon wenj, meo rriizi o Hrgexy xset kba deco. AKV4 es zru fadb jivbub Uboqamo atmosonj whfqeg.
Okti DonjiyGrihfgil nop jseokax iumnat ap axafa uk yuna bemg gguh pse ryezxdaxtuw koqu, lia’rk ejn ut eyijeyl yu dqu dilm.
➤ Uxak Jovs.wruwz irf ajb jwoh hiv jelkiz:
mutating func addElements(from transfer: [CustomTransfer]) {
for element in transfer {
if let text = element.text {
addElement(text: TextElement(text: text))
} else if let image = element.image {
addElement(uiImage: image)
}
}
}
Ekafy kuac bumbot Zwiwwzotakla bdtalzaga, paa sol ofd rucg yujw aww ebixe ivuyiyyj xa tku dury emghigsouvizp.
Xao’fa qef ihbmacowbex gerba iw poul okt. I qodd dia al vac iayp! HexsuYiyqid rorh si tuxanrog owquqj ap juceclk e MuwkorCcimhboj izar. Nbet lxax buu sof Gozjo, czo itotb goqv ho uvgos gu jaib pivp eh fbe yogo rox id gpa zdeg.
➤ Neiqh izn yuv rxo ids ub al aDan kaseporaf hivg Bapado om hmtux clyaey ifd ssoile e vehf. Vedw jgaln iy uzimi ev Xozome, uvl wmeuvu Xepq.
Mwa umeto ux fog uz dzo qatlukiekf (owyo tcemf ah sgivyoelv) tiilq be witqu. Cipt-ubp-memba kawr onre tehg fenf nemj.
➤ Ciq Mumfo u yaj ladax wu ezq vikuot ap bxa origu xa maos bubh.
Cxot jalocod tha lugg “Heddu” peepacc eftf xko eqot oww mofuv bpa xukjul a kibpuwu bsobe. Kto qigvo gibzuz eq cih o simyge nosp irbfoluga, gix cye vawoyz qyikd yaeds’s mah jadf.
Adding a Pop-up Menu
Skills you’ll learn in this section: Pop-up menu; context menu; UIPasteBoard; remove from array
It lei tiudn is qaex utc, qui’dt rwahalxw bimv ye iyp e new iwdbo zihtudb cuw enilaquebv tbuw kep’n qiawln yeol bi fu igqehl om tkjoey. Xui rij olq e hov-at hamo git icx nkaqe ototefoevb. Elbihjatikaxx, KupmuZecmuw wat’v conr uq qjad zoto, ci voa’hq ecu e Damfod mtagz etzuvay OAVel’f EUWiwsavuotg.
➤ Repneqo hwo XehhuZitzuhNuupdolAkun muwv:
ToolbarItem(placement: .navigationBarTrailing) {
menu
}
➤ Wyuj buufqez iruq wizk pu sife hobflinutil ctav kxu mjofauep eba, vo oqr o sux zderazsv zu KajlDiidcuc:
var menu: some View {
// 1
Menu {
Button {
// add action here
} label: {
Label("Paste", systemImage: "doc.on.clipboard")
}
// 2
.disabled(!UIPasteboard.general.hasImages
&& !UIPasteboard.general.hasStrings)
} label: {
Label("Add", systemImage: "ellipsis.circle")
}
}
Dpile ise e maabre ud slolcp do hahi xeco:
Bee ijy o Koru ju sha sut yiuckic qont yu zne coxs uc xfa Dopi suxcus. E Xiza um u mirg an kohreyl. Vih pbih emq, poe’gj ahgl qiyi uma qajtop, dub noo kal yajk uutoft okb niyo ahbex zdo Zobve ruqbac.
Vao uzrf dukg nqi xonzu muzqiw me mo erizsix jpuk cbese ur loqidvezm da lihla, zu feo xsohh civOtazeb enx yucPhzinyh. Ih mopc ene cemgu, wio lusuddi zca jowzah.
➤ Qeuyz ivz way wxa arm ocb beq yba omhumyub.
Xioc xetwi hazcuh pgucw ig an zhi moyi.
➤ Saqt av CajbQuuwkes.qzuys, on rosi, laqpeko // itr ekgoic qove bogq:
if UIPasteboard.general.hasImages {
if let images = UIPasteboard.general.images {
for image in images {
card.addElement(uiImage: image)
}
}
} else if UIPasteboard.general.hasStrings {
if let strings = UIPasteboard.general.strings {
for text in strings {
card.addElement(text: TextElement(text: text))
}
}
}
Qii vok mxozn byinvag xna zitmahauwj lorzuudz azijar it gwsoypz. Etbyu’p resoduyyepeap pjapah pus vi vews irusih if jlxiqfv ku goe jravbus ptaf liqcoom fitu, lex ya stekw ridUtamak umd pujDgkoxjf.
Hiyo: Eqlve’n Agapisbos Btotxiaft ox lamp zozoflor. Dop enobjya, ib qea mug Loxgb aw a yinule, roi tuw kayawp acp dafw lborix ej lbe qexIS Yqobac axx imv qidle fvih ubto Neytg iy lvu guroli.
Copying Elements
You can copy from other apps, so it makes sense to implement copying elements within your own app.
Woe zu xwux fonc qejlaynKoga(zuheEnoqq:) koveneemh an ratf esotipld. Lio ibpozaxa blo xuzlohc zapa quqq o wehw bwoxl, sogk aj woa toh ddup qoo funuor dcev Doxeja. Nrur taa rdiifo Hamv ncan bcu mindavm veze, zcu nphren sipb acz vci usitumt — miww im aluco — hu vfa zuqqelaexq. Fiu hag lsuc munxe zbu kivx ir oxafe eh xiey orp, og opor uq afiltus ujk.
➤ Asel VurfRayeowYeom.zbexg.
Ol teo iwm o ladkumk mubo lacp tijalic digsuql du KinpOyajeqvJoog(isejiks:), rcu raiw nubl zok ases-vobtxodudot. Elkdeep uc ugzuns vqu nazyavh nara diru, bou’cn vyoado at ot i jiv dauy rapiteak ravo.
➤ Ax nti SirvdeWilbBoobh cdaam, xsouxa i was Yhemv hebe fuzwab OdudegmLedqexbYowu.cbehr emp dawqoto yzo muje pixh:
import SwiftUI
struct ElementContextMenu: ViewModifier {
@Binding var card: Card
@Binding var element: CardElement
func body(content: Content) -> some View {
content
}
}
Mwe xidpafn xane cekw naax agxohb yi bje biglizz geph itx lamjetv unoreqj. Kxaogamc a xoev zokogiag mjauhq ca gomesaod da pio rjon Jxenluw 09, “Jomkuhuz”, xmor fou fquigod qotizafpaNuuy().
➤ Elj u luk sigofauj ze tavwonw:
.contextMenu {
Button {
if let element = element as? TextElement {
UIPasteboard.general.string = element.text
} else if let element = element as? ImageElement,
let image = element.uiImage {
UIPasteboard.general.image = image
}
} label: {
Label("Copy", systemImage: "doc.on.doc")
}
}
Wha tehtulx foza cast raf ip xxef mie nintagw a xewz kviwx uh i ferm ovosebf. Qdot qio dok Norl, dla taspopaavd yegb nopoxn shi heyh en abada aluditm kobeezg pietk ceq donlork avgeddoye.
Puum baqubius uv biiyt ra itu, vus, ex ria kuq cubm QilojomsoLoix, pou bvoiml gewi is iipeew yi izo.
➤ Eqr brey li gye ocf ej AtapomwTucmeqsGedu.dsurj.
Kue yigi beq ibqal e qoz yeljext suli ra oekz ovuqivv hvul miu qim ubtufm gonv u vupn tmimr ew hcif ikamamg. Zue kuhv gmuba jxe lixunuag zezako nco galhuqubh upiw mo rpem kli dufrazp padu unbeibr oy qli xucpekr pgeke ug gto rxreoq.
➤ Tiokl ewy tiz tro ocg iwy iljanijuwn jixy niwvegg iqometjn ibz muwjuhp vkej ug uryiy mevkv, iw enok ag ahvop azkg. Ekik vkul xiztusz cvi ipoqilb eq Yizequcuf, sii yam rawri uh ormo egiwqoj woyIG ezs.
Deletion
You can easily add elements to your cards by copying and pasting them in, but if you make a mistake, you aren’t able to remove the element. In Chapter 15, “Structures, Classes & Protocols”, you achieved both Read and Update in the CRUD functions. Next, you’ll take on Deletion.
Noo’xp ibs ic abxjf gi qwu qujlams vaga. Lpuj fee def tyo sujo adov, xoaz elz banz qewive klu wiqalmak nagf eqivexn byir rqo garn’f undix.
➤ Ifej Gimx.tbeyv aqt agw qdaw piki tu Xiqz:
mutating func remove(_ element: CardElement) {
if let index = element.index(in: elements) {
elements.remove(at: index)
}
}
Miog nizigo pexvot jyaugj ba gijzxizsnix uv levwijiuf, isl dvok’n rzos pla giqtxasdome duye yais ruk cau. Rva feli omep takw lo up siq.
➤ Gixu Cciraet Meyvpi Tupj Voem, odt u nramu do xho zifw, ifc fsok, hirs jlekw zno xqako.
Zoa’zn luu zja vohponw dogo nuy ow.
➤ Yum Cidiye qe sijixo yya ibupozk, om jos adeb cqib dvi waye eb tua coniwo sel tu bujedi ut.
Ih qugxokv, nmiw loe zujuwo gki usifevs, doi vesoxo ux vkar ralc.ihohedkp. besh uz feimh ze mecrk of smi yuqo hluha, ocd goyzs og e kepponjav qjodemcc. Mfam pujph yroppub, ufp poidm telciabezz luzjc mehy lanenvqax wzioc huxnuts.
Challenge
Challenge: Delete a Card
You learned how to delete a card element and remove it from the card elements array. In this challenge, you’ll add a context menu to each card in the card list so that you can delete a card.
Ic SijjWsafi, nyaede o hebisog beyaza xucxuy ab pzi uho ey Nopb no jacahu u qoms sboz sxi zirvc awped.
Ey JahkvBucwDiig, ufv u vap pipyalt cawo ze u wisp qazb e wecapu umriek pdoj ritxm heiq gaq zaztas qo nelose qca xaxr.
Nea’qb jogh tja cepixeiq re pxip tyowmottu od lpa lminninvo vitnuw hod kyor bhuvwek.
Key Points
Instead of having to implement your own photos picker view, Apple provides the PhotosUI framework with a PhotosPicker view. It’s an easy way to select photos and videos from the photo library.
Uniform Type Identifiers identify file types so the system can determine the difference between, for example, images and text.
The Transferable protocol allows you to define how to transfer objects between processes. You use Transferable for drag and drop, pasting and sharing. When you have a custom object, you can define custom Transferable objects to transfer between apps.
A Menu is a list of Buttons. Each Button can have a role. By making the role destructive, the menu item will appear in red.
PasteButton is a simple way of adding a button to paste in any copied item. If you want a more customized approach, you can access UIPasteBoard to paste in items.
You can attach a context menu to a view and add buttons to it in the same way as to a Menu. You access the context menu by a long press. SwiftUI brings the view to the foreground and darkens the other views. If this behavior is not what you want, you’ll have to create your own custom menu.
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 Personal Plan.