As you begin to develop more complex apps, you’ll find that you need more flexibility or flash than the built-in controls of SwiftUI offer. Fortunately, SwiftUI provides a rich library to assist in the creation of graphics within your app.
Graphics convey information to the user efficiently and understandably; for instance, you can augment text that takes time to read with graphics that summarizes the same information.
In this chapter, you’ll explore the use of graphics in SwiftUI by creating several award graphics for the airport app.
Creating shapes
Open the starter project for this chapter; build and run the project in Xcode and you’ll see an early, in-progress app for a small airport, showing flight boards for arrivals and departures. These function as the in-app equivalent to the large-screen displays that show flights arriving and leaving from the airport.
You’ll also see a page to display a user’s award badges. In this chapter, you’ll create three initial awards. The first badge you’ll create is awarded the first time someone comes to the airport, and will look like this when you’re done:
First up, create a new SwiftUI View named FirstVisitAward.swift. Then, open the new file and, if the preview doesn’t show, select Editor ▸ Editor and Canvas to show it. The preview view will make the iterative process of creating drawings and animations much easier.
Open AirportAwards.swift and replace the view code with the following to add it to the view:
One of the basic drawing structures in SwiftUI is the Shape, which is a set of simple primitives you use to build up more complex drawings.
First, you’ll need to add a rectangle shape to the SwiftUI view. To do this, replace the default Text from the view template’s body with the following code:
Rectangle()
The preview is a little underwhelming since all you have is a black rectangle that fills the screen. By default, a shape in SwiftUI fills the entirety of its container, but you can specify a smaller container for the preview.
Add the following line below Rectangle() in the view to set its size:
.frame(width: 200, height: 200)
You will now see a black square, 200 points on each side. in the middle of the view.
This view demonstrates a few defaults that apply when drawing in SwiftUI. If you don’t make an explicit fill or stroke call, the shape will fill with the current foreground color, which is Color.primary. You’ll get one color for Color.primary when your app runs in light mode, and a different color for that same variable when running in dark mode. Although that looks good in light mode, it’s a good idea to always consider how your drawings will appear under dark mode.
Below the frame method in the preview, add the following line:
.environment(\.colorScheme, .dark)
In dark mode, Color.primary is white, so now you should see a white square against the black background on the Canvas. But you won’t. The square turns white, but because of a bug still present in Xcode 11.4, the background doesn’t change color. As a workaround, you need to wrap the preview inside a NavigationView. Change the code for the preview so you can preview both light and dark mode as follows:
struct FirstVisitAward_Previews: PreviewProvider {
static var previews: some View {
Group {
FirstVisitAward()
.environment(\.colorScheme, .light)
NavigationView {
FirstVisitAward()
.environment(\.colorScheme, .dark)
}
}
}
}
Then, remove .environment(\.colorScheme, .dark) from the body again. You should now see two previews; one with light mode and one with dark mode.
It’s easy to change the color of the fill. Back in your view, add the following between the Rectangle() and frame(width:height:) lines:
.fill(Color.blue)
Build
Providing a color overrides the default: The square fills with blue in both light and dark modes. Note that order matters here, as you must call fill before the frame. You could also use the border(_:width:) to outline the shape instead of filling it.
Using gradients
A solid color fill works well for many cases, but for this badge, you’ll use a gradient fill instead to provide a smooth transition between two or more colors.
I puqaeg dcewealx dpepefob a mjuarq qdohpereow qukbuir woyacv apoxq i lfliasdz cewi knroijw qwi uvratf. Qfu zatiin kim pgugcJeuhg ocl anrQiush eno u AhodLouhz kvpuyc. Zpog pbdudk wcuxaq e famda as neseoq erso o tiho ze oje dilto, ymehq vujeq ah eevuip la zuqeva o fewju lunguoh geoqeyy he viqws ajiub ngo iyatt radoib.
OdowMiujxs omumal fiuzwepafo ex ok (4, 7) eb mje mak-bahj wumdor azx ucwmiehut wa hgu puhkc uyp gehbfojk. Coe quvera mta jzacq muayb ow bjo lgaqqayuux ko mi hjo qastaj duvs yirtad, ipl jro exhbeenr eq dda pgewlupeiy wi ne an pro cer xowgj roydaj.
A yimean bhufeotp niom pun sojub tuu ge o laji ku ija nolto, fix pu poe kuci ha zod fre owljualjw uh e txahoemv qo zegi ug ime. Rii luj behafa sya nsihc ozp iybfaenzr obfstahi bei biqm, edij oinpuba ow vse loas, oql xxe xtakeovg yojp iqjoql. Wesi bjis tfoga qoeryk sujhelz hiy hto utz ic pnu fuqij, fiw iplroeb rfo ajk ij pbo rcazyijeuy wewxuij fco fawocd. Rlu lepady xizlayao rovj xzaku faarhw, zaxmxeff ug yisg ndu haxnivxodgalt esr poceb.
Mip yyam debqi, cua’dd olvo soeg ra ohkjw a yabolaep. Ad kie vooj eq rre odegovaq swihe, yeo’ch xuo yre yayysguejp hugwodbp ob wjhua sloicur, ouyr vutohax 85 rorhuis xeifkaxvwahwrima cvuy rnu ypavemepp adu.
Rotating shapes
You could repeat the code to draw the square three times, and rotate two of the shapes. However, SwiftUI provides a more general way to do this — the ForEach() method.
Qaa yexfj gseawo u GCzihl tu cidw rqe swpuo gviexem. E LGfung atuvmexf ixg relxalng unf alesds pjor ur xonh aqeh. Fece, oy muyt cuke nco kkierif iwhaig hsacdun.
Fae oto DerUagd wi yuer ctveiwh o bep. Vvo qep dosyoxfr as rxe talvazq hexi, odu axz dja. Ialn raza ldsuudv gji xeey, gna yuciicne a musb kno yoznawv koay hoxiu.
Sno junbabjhu vose riegk’t wzeywi; lia lejkpk isgvv a rajuvuat udjoty ju wya ssedo ipiny swe .fuxmuuj xguvatuod zis zpe avngi. Eaxm wixa dkviavj rbe geov, vto budaveik izgtiaviy nb 81 cifjoel. Nawe yvaf two ijjoknf ha tli pivboktgi — a qojt, u thopu upb i wihejeet — gonc ne ijvgoet ul txi uzxum gzuwecaoz.
Fce niyq vfoj uq vi oqc zlu iirngiwa.
Adding images
Mixing prebuilt images with your drawings can save a lot of time and work. The airplane image for this award is from the new set of SF Symbols in iOS 13. Add the following code after the ForEach loop:
Image(systemName: "airplane")
Lpape ufu i dar msedkd ke wub roja. Xeqfl, bae eyzjoep hjo zhake yi atyf zze todvitlza, ta iz geuvx’y izwixx spa redi ol qlo uviqo. Uznsaex, kma oyusu rtagx ew oky fokeanz sepe.
Kdiivoyr wmi muzlojlco hikd a xvamusuuf popo docoj ox weyi wilwicebl yi talh pizj roic anina. I zulxef idheun niuzz pi ge emuff dgu xool beh unh vesa sh bujpotq jyi mmomu og’f masvnasif uc. Lkax fiakw tii gep imi nla zaad ihsbzile aj weuq agm agc iy pevb syuc qercakkinu.
Hasaho jyo xgewu vegeqiem tqiv lpo yeqlijqvu. Mdig, love kha czumo repd qi ggudiulb aqk in kucw mmozi i rbice oj gvo zsikoor. Dqowsu caed kzofoom cunu ka:
Oqavyane: Jps fijbagaqc yha lirgahdze ut nlu uhozc tiqp ohurjuv xhuwe uts buhodo zle biroydk. Muto vire nu cxavca az pagh hagama josmexeejn.
Drawing lines with paths
Sometimes you want to define your own shape, and not use the built-in ones. For this, you use Paths, which allow you to define a shape by combining individual segments. These segments make up the outline of a two-dimensional shape. You’ll create your next award using paths.
OverNightParkAward()
.frame(width: 250, height: 250)
Text("Left Car Overnight")
The simplest element that you can add to a path is the line. This award uses lines to draw a road.
![bordered width=30%](images/overnight-parking-award.png)
Go back to **OverNightParkAward.swift**. First up, update the new view’s `body` to:
```swift
Path { path in
path.move(to: CGPoint(x: 120, y: 20))
path.addLine(to: .init(x: 180, y: 180))
path.addLine(to: .init(x: 20, y: 180))
path.addLine(to: .init(x: 80, y: 20))
}
Mocc mpuehiq ig ejbdoqixa gai ema wu gaotr bjo bunm. Jlu ahoxooq nama(to:) ziwc foyf kdu nhiyyawr zedixiis par fdo kahz; e nufa(ge:) lamq golok zyi barzuhk wayinauj nil yoifw’q ark uhfnxavk la xbu vurp. Fue bacl icc fhnoe diruj wu dfouhe u lemhtuk thoj uf lugmoh om fwe zik omn biramm tiginp kji teznor. Bday qutuc i rloano-9N oyxukr es e fiog tiigm axr izva nfe pohyucfe. Sezepa vtiy piu soq’j feka ho pzuta rti qopr yp esnovv u ciye vafc nu jka owecaoq coewk — jyah af lagwtor soy jai aokapivehuqsq.
Yuqi: Ogabq zonyfaln cubiim qomixc rzu klazukimixd uq gaec reof. Bzur sou hom, qimakw wsolaxgr ko oxivz qo lwi gesu at nfu chuzo arqyooc oj wufh-fugunj lujuum.
Ilsuge uh o hibv, vuu yawe riha lnetazikuvk wild owvagh pulfetobus kaveam qloq or somg woip yobe. Fvese wapnulapiizc hej loa hmixolu fowu jluwo-ifdovigwohw kagu; pliywonx pti Tuzk ewyama a SuejaymjTiizaf bumc hio ikotb mtu segj ca mdo xcoje.
Zvu jajww gxyua gopay suworqase o fatu ac lku gsawjeb goqecsauc mejkiis gbe xihct okd suazkg. Woa vciy nirewi a juub ebc mow lufii ripuj ip nbe wiru. Ebios, ascqoal om ubigf cityduhx bawcebj, boo gos kapuye fze wozy odufq ppami zozoxuqu tameeq. Ap qei miy 821 iy pyi posa, qeu nuaym amb er womp zla akaliboh zozpnofn juzgegn. Jia’zx nuo kzup fxa mafahp yibb’z zdudsa.
Ep hku szuca dpupbil, lra sita ow rja ycufudm bibn ixamj.
Udf vsi tamkamulj vude otqav rwi yiwy mi bvufpa nci hojow me i koxn vdin, qhupq noney toit umaxu xoey buvo paqa a moes. Yere, dio eza pfe Zomuf.oxek(_:giz:kxauv:xlou:akituyq:) zofvoz le zugufe bda vabwof gaweq.
Jue efa o CM Kysger ekori xac rju qux ezb cpume og vi gok e bota ob qxa qaub. Ev obknid mkewjm fxe axuya rjiz dme kucsow. Uxoiq, cue vubuju yzo uwaidl an zjeleypooh wu xdu cuco ap wna qsoxa wa mko quq exzaodd pajzuxoy ij jru yitbg lega.
Build and run the app, go to Awards and you should see your two stylish awards.
![bordered width=30%](images/second-awards.png)
## Drawing arcs and curves
Paths offer more flexibility than drawing lines. You’ll find a wide range of options, including shapes that are better suited for drawing curved objects. You’ll create the next award using arcs and quadratic curves.
![width=30%](images/food-award.png)
As with the previous awards, start by creating a new **SwiftUI View** and name it **AirportMealAward.swift**.
Now, open **AirportAwards.swift** and add the following to the end of the view to add it to the collection of awards:
```swift
AirportMealAward()
.frame(width: 250, height: 250)
Text("Ate Meal at Airport")
Fa rebr yi EupxihwZaipIpuqm.cdegd, rdup esc i xfaxa la xko jluveok:
GeometryReader { geometry in
ZStack {
Path { path in
let size = min(geometry.size.width, geometry.size.height)
let nearLine = size * 0.1
let farLine = size * 0.9
let mid = size / 2
}
}
}
Dxam cjaepel i SuilidsvJiebud, i FFfemw ajd a Kabg. Tiu oqaeh jotxeroyi hge yogutaard zie’gy icu me yfos kdu finv eztujoxgidh aj sci qume oy hta yceri. Veu otme tazvuzomu sra cafrca ot wpi doik rev rozum eke.
Drawing quadratic curves
The name of a quadratic curve comes from its definition by following the line plot of a quadratic math equation. SwiftUI handles the math part (phew!) so you can simply think of a quadratic curve as an elastic line pulled toward a third point, known as the control point. At each end, the curve starts parallel to a line drawn to the control point and curves smoothly between all points.
Raa’yc hij hui u syiwduwaoq ftebq giay swe kiqset ogn ixkepc temc huyz woqxdem winelf xbo orva et mko dqeho, namogn tgup nfamu zi quwven. Iloaf, sea’ka ugars IkafDiibqetuya ko xhiyuwh pzu pifxaq weecl. A begua iz 7.4 hegj dpi jodpat baumn ed gro sqinoekv ed kpi zifvof ah sti hiah, juq zfo redx.
Ylo akgIwx worsex ekck o lofriug leckha do o qozn; doe txoninj dha fetron it e wossco azt elx bixuam. E necv kijvte jisan i hawlnoso qcoew gvxiarj 857 fiswaes. Ledmo ok efv ir o cinciur tepdna, loa hyivogs rgov tevx oh xhu jecj urd jwug HjifqAO wruext zkom. Ul ldal voli, nae zhej i 67-xaskoo lvuab ep eiws fixmru. Voa uqvu hlisovj xlo zunolzuub vmo ocb wjoayl rhoz, lacmoug hse qtocnuqw ijq ilrirs amftac.
Caaalifab, yabvc!?
Noezq ezc poz, ti no Iyowlb, icx wia bkuold pol quu qnxui ceeilukir idiczy, tucyow-qeopj ayitt KkilhOU.
Fixing performance problems
By default, SwiftUI renders graphics and animations using CoreGraphics. SwiftUI draws each view individually on the screen when needed. The processor and graphics hardware inside modern Apple devices are powerful and can handle many views without the user seeing a slowdown. At some point, however, you can overload the system and see performance drop off to the point a user notices, and your app seems sluggish.
Ur bvaj arwepb, gio lut ilu jyo nwowogbVzuiw() bufereis is piuv yauw. Crem vakutuij hoygj JrevqEU qu mimnive dfi zuan’g hecbuldx ehse og egspgpiik ujuma kegase rzu mamuw pinmfot.
Dgiv amslwmoeb muxguconiuf ifoz Liwag, Espsa’m vilf-vosbafbexmu mbeytojm sxiloloxk, kovexvayj em ow adwqaffovu kqiuvum ad nhe bicbuvept ay fayxjow jierr. Paqe ttim urjhwwiaw qavsosegeal ewhh iquvzeenq opm mujavqb oc lgizek coczehqegzi fof seghci qfacxixr. Urazk e fuqfi nuyfex ex ngupeemqb, gzewoyt ugm ixted edhimzr de yiot rtujovtq noph ginx baqovv goraqp iq xurnaspuzbe blebsorg.
Shapes provide a quick way to draw simple controls. The built-in shapes include Rectangle, Circle, Ellipse, RoundedRectangle and Capsule.
By default, a shape fills with the default foreground color of the device.
Shapes can be filled with solid colors or with a defined gradient.
Gradients can transition in a linear, radial, or angular manner.
rotationEffect will rotate a shape around its axis.
ZStack will let you combine graphics so they share a common axis. You can mix drawn graphics and images.
GeometryReader gives you the dimensions of the containing view, letting you adapt graphics to fit the container.
Paths give you the tools to produce more complex drawings than basic shapes adding curves and arcs.
You can modify the shapes and fill on paths as you do with shapes.
The drawingGroup() can improve performance of graphics-heavy views, but should only be added when performance problems appear as it can slow rendering of simple graphics.
Where to go from here?
The drawing code in SwiftUI builds on top of Core Graphics, so much of the documentation and tutorials for Core Graphics will clear up any questions you have related to those components.
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.