#WWDC19••

Building Custom Views in SwiftUIGraphic effects and layout

Dave Abrahams
John Harper© 2019 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple.

Layout Basics

struct ContentView : View {var body: some View {Text("Hello World")}}

Hello World

Layout Basics

struct ContentView : View {var body: some View {Text("Hello World")}}

Layout Basics

struct ContentView : View {var body: some View {Text("Hello World")}

Hello World

}

Text

Layout Basics

struct ContentView : View {var body: some View {Text("Hello World")}

Hello World}

ContentView
Text

Layout Basics

struct ContentView : View {var body: some View {Text("Hello World")}

Hello World}
Root View
ContentView
Text

Layout Basics

struct ContentView : View {var body: some View {Text("Hello World")}

Hello World}
Root View
ContentView
Text

Layout Basics

struct ContentView : View {var body: some View {Text("Hello World").edgesIgnoringSafeArea(.all)

Hello World}}
Root View
ContentView
Text

Layout Basics

struct ContentView : View {var body: some View {Text("Hello World")}

Hello World}
Root View
ContentView
Text

Layout Basics

struct ContentView : View {var body: some View {Text("Hello World")}

Hello World}
Root View
ContentView
Text

Layout Basics

struct ContentView : View {var body: some View {Text("Hello World")}

Hello World}
Root View

ContentView
Text

1. Parent Proposes Size for Child

struct ContentView : View {var body: some View {Text("Hello World")}}
Root View

ContentView
Text

2. Child Chooses Its Own Size

struct ContentView : View {var body: some View {Hello World

Text("Hello World")}}
Root View

ContentView
Text

3. Parent Places Child in Parent’s Coordinate Space

struct ContentView : View {var body: some View {Text("Hello World")}

Hello World}
Root View

ContentView
Text

Layout Procedure

1. Parent proposes a size for child
2. Child chooses its own size
3. Parent places child in parent’s coordinate space

Layout Procedure

1. Parent proposes a size for child
2. Child chooses its own size
3. Parent places child in parent’s coordinate space

Layout Procedure

1. Parent proposes a size for child50

2. Child chooses its own size
3. Parent places child in parent’s coordinate space

10

struct TrippyBadge : View {var body: some View {Image("ColorWash").frame(width: 50, height: 10)
}
}

Frame
Resizable Image

Layout Procedure

1. Parent proposes a size for child50

2. Child chooses its own size
3. Parent places child in parent’s coordinate space

10

struct TrippyBadge : View {var body: some View {Image("ColorWash").frame(width: 50, height: 10)
}
}

Frame
Resizable Image

Layout Procedure

1. Parent proposes a size for child
2. Child chooses its own size
3. Parent places child in parent’s coordinate spacestruct WedgeChart : View {var body: some View {Image("Wedges").aspectRatio(1)}}Aspect Ratio View
Resizable Image

Layout Procedure

1. Parent proposes a size for child
2. Child chooses its own size
3. Parent places child in parent’s coordinate spacestruct WedgeChart : View {var body: some View {Image("Wedges").aspectRatio(1)}}Aspect Ratio View
Resizable Image

Layout Procedure

1. Parent proposes a size for child

Hello World

2. Child chooses its own size
3. Parent places child in parent’s coordinate spacestruct ContentView : View {var body: some View {Text("Hello World")}}

Root View
TextLayout Procedure

1. Parent proposes a size for child
2. Child chooses its own size
3. Parent places child in parent’s coordinate space
4. SwiftUI rounds coordinates to nearest pixelLayout Procedure

1. Parent proposes a size for child
2. Child chooses its own size
3. Parent places child in parent’s coordinate space
4. SwiftUI rounds coordinates to nearest pixelHello World

struct ContentView : View {var body: some View {Text("Hello World")}}

Root View
Text

Hello World

Delicious Avocado Toast

struct Toast : View {var body: some View {Text("Avocado Toast")}}

Root View
Text

Avocado Toast

Delicious Avocado Toast

struct Toast : View {var body: some View {Text("Avocado Toast").background(Color.green)}

Root View}
Background

Text

Avocado Toast

Delicious Avocado Toast

struct Toast : View {var body: some View {Text("Avocado Toast").background(Color.green)}}

Root View
Background
Text

Avocado Toast

Delicious Avocado Toast

struct Toast : View {var body: some View {Text("Avocado Toast").background(Color.green)}}

Avocado Toast

Root View
Background
Text

Color

Delicious Avocado Toast

struct Toast : View {var body: some View {Text("Avocado Toast").padding().background(Color.green)}}

Avocado Toast

Root View
BackgroundPadding

Text

Color

Delicious Avocado Toast

struct Toast : View {var body: some View {Text("Avocado Toast").padding().background(Color.green)}}

Avocado Toast

Root View
BackgroundPadding
Text

Color

Delicious Avocado Toast

struct Toast : View {var body: some View {Text("Avocado Toast").padding([.leading, .trailing]).background(Color.green)}}

Avocado Toast

Root View
BackgroundPadding
Text

Color

Delicious Avocado Toast

struct Toast : View {var body: some View {Text("Avocado Toast").padding(10).background(Color.green)}}

Avocado Toast

Root View
BackgroundPadding
Text

Color

Delicious Avocado Toast

struct Toast : View {var body: some View {Text("Avocado Toast").padding(10).background(Color.green)}}

Avocado Toast

Root View
BackgroundPadding
Text

Color

Delicious Avocado Toast

struct Toast : View {var body: some View {Text("Avocado Toast").padding(10).background(Color.green)}}

Avocado Toast

Root View
BackgroundPadding
Text

Color

Delicious Avocado Toast

struct Toast : View {var body: some View {Text("Avocado Toast").padding(10).background(Color.green)}}

Avocado Toast

Root View
BackgroundPadding
Text

Color

Delicious Avocado Toast

10

10

10
struct Toast : View {var body: some View {Text("Avocado Toast").padding(10).background(Color.green)}}

Avocado Toast

Root View
BackgroundPadding
Text

Color
10

Delicious Avocado Toast

10

10

10
struct Toast : View {var body: some View {Text("Avocado Toast").padding(10).background(Color.green)}}

Avocado Toast

Root View
BackgroundPadding
Text

Color
10

Delicious Avocado Toast

struct Toast : View {var body: some View {Text("Avocado Toast").padding(10).background(Color.green)}}

Avocado Toast

Root View
BackgroundPadding
Text

Color

Delicious Avocado Toast

struct Toast : View {var body: some View {10

Text("Avocado Toast")

10.padding(10).background(Color.green)}}

Avocado Toast

Root View
10

BackgroundPadding
Text

Color

Delicious Avocado Toast

struct Toast : View {var body: some View {Text("Avocado Toast").padding(10).background(Color.green)}}

Avocado Toast

Root View
BackgroundPadding
Text

Color

Delicious Avocado Toast

struct Toast : View {var body: some View {Text("Avocado Toast").padding(10).background(Color.green)}}

Avocado Toast

Root View
BackgroundPadding
Text

Color

Delicious Avocado Toast

struct Toast : View {var body: some View {Text("Avocado Toast").padding(10).background(Color.green)}}

Avocado Toast

Root View
BackgroundPadding
Text

Color

Delicious Avocado Toast

struct Toast : View {var body: some View {Text("Avocado Toast").padding(10).background(Color.green)}}

Avocado Toast

Root View
BackgroundPadding
Text

Color

Scrumptious Avocado

struct Avocado : View {var body: some View {Image("20x20_avocado")

20

}
}

Root View
Image

20

Scrumptious Avocado

struct Avocado : View {var body: some View {Image("20x20_avocado")

20

}
}

Root View
Frame

Image

20

Scrumptious Avocado

struct Avocado : View {var body: some View {Image("20x20_avocado")

20.frame(width: 30, height: 30)}}

Root View
Frame
Image

20

Scrumptious Avocado

struct Avocado : View {var body: some View {Image("20x20_avocado")

30.frame(width: 30, height: 30)}}

Root View
Frame
Image

30

•

This Is as It Should Be
There’s no wrong way to do itHStack and VStack★★★★★
5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack {★★★★★

VStack {Text("★★★★★")

5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

Text("5 stars")}.font(.caption)
VStack(alignment: .leading) {HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack {★★★★★

VStack {Text("★★★★★")

5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

Text("5 stars")}.font(.caption)
VStack(alignment: .leading) {HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack {★★★★★

VStack {Text("★★★★★")

5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

Text("5 stars")}.font(.caption)
VStack(alignment: .leading) {HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack {VStack {Text("★★★★★")
Text("5 stars")}.font(.caption)★★★★★
5 stars

VStack(alignment: .leading) {Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack {VStack {Text("★★★★★")
Text("5 stars")}.font(.caption)★★★★★
5 stars

VStack(alignment: .leading) {Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack {VStack {Text("★★★★★")
Text("5 stars")}.font(.caption)★★★★★
5 stars

VStack(alignment: .leading) {Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack {VStack {Text("★★★★★")
Text("5 stars")}.font(.caption)★★★★★
5 stars

VStack(alignment: .leading) {Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack {VStack {Text("★★★★★")
Text("5 stars")}.font(.caption)★★★★★
5 stars

VStack(alignment: .leading) {Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack {VStack {Text("★★★★★")
Text("5 stars")}.font(.caption)★★★★★
5 stars

VStack(alignment: .leading) {Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack {VStack {Text("★★★★★")
Text("5 stars")}.font(.caption)★★★★★
5 stars

VStack(alignment: .leading) {Avocado Toast

Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}🥑HStack {VStack {Text("★★★★★")
Text("5 stars")}.font(.caption)★★★★★
5 stars

VStack(alignment: .leading) {Avocado Toast

Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}🥑HStack {VStack {Text("★★★★★")
Text("5 stars")}.font(.caption)★★★★★
5 stars

VStack(alignment: .leading) {Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack {VStack {Text("★★★★★")
Text("5 stars")}.font(.caption)★★★★★
5 stars

VStack(alignment: .leading) {HStack {Text("Avocado Toast").font(.title)

Ingredients: Avocado, Almond Butter, Bread, Red Pep…

Avocado Toast

Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack {VStack {Text("★★★★★")
Text("5 stars")}.font(.caption)★★★★★
5 stars

VStack(alignment: .leading) {HStack {Text("Avocado Toast").font(.title)

Ingredients: Avocado, Almond Butter, Bread, Red Pep…

Avocado Toast

Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack {VStack {Text("★★★★★")
Text("5 stars")}.font(.caption)★★★★★
5 stars

VStack(alignment: .leading) {HStack {Text("Avocado Toast").font(.title)

Ingredients: Avocado, Almond Butter, Bread, Red Pep…

Avocado Toast

Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack {VStack {Text("★★★★★")
Text("5 stars")}.font(.caption)★★★★★
5 stars

VStack(alignment: .leading) {HStack {Text("Avocado Toast").font(.title)

Ingredients: Avocado, Almond Butter, Bread, Red Pep…

Avocado Toast

Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack {VStack {Text("★★★★★")
Text("5 stars")}.font(.caption)★★★★★
5 stars

VStack(alignment: .leading) {HStack {Text("Avocado Toast").font(.title)

Ingredients: Avocado, Almond Butter, Bread, Red Pep…

Avocado Toast

Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack and VStack★★★★★
5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack and VStack★★★★★
5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack and VStack★★★★★
5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack and VStack★★★★★
5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack and VStack

VStack {ListCell()
Toggle(isOn: $on) { ... }}★★★★★
5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack and VStack

VStack {ListCell()
Toggle(isOn: $on) { ... }}★★★★★
5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack and VStack

VStack(spacing: 4) {ListCell()
Toggle(isOn: $on) { ... }}★★★★★
5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack and VStack★★★★★
5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

‫‪HStack and VStack‬‬‫★★★★★‬‫نجوم ‪5‬‬‫خبزة محمصة مع‬‫املكونات‪ :‬أفوكادو‪ ،‬زبدة لوز‪ ،‬خبر‪ ،‬رقائق فلفل أحمر‬How Stacks Work

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack {Deli…

Text("Delicious")
Image("20x20_avocado")

Avocado…

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack {S₀

Delicious

Text("Delicious")
Image("20x20_avocado")

S₁

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work
S₀ + S₁
HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Workw

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Workw
HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Workw

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Workw
HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

S₀

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

S₁

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack(alignment: .center) {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack {Delicious

Text("Delicious")
Image("20x20_avocado")

Avocado Toast

Text("Avocado Toast")}
Parent.lineLimit(1)HStack
Text

Image

Text

How Stacks Work

HStack {Text("Delicious")
Image("20x20_avocado")
Text("Avocado Toast")}.lineLimit(1)Delicious

Avocado T…

How Stacks Work

HStack {Text("Delicious")
Image("20x20_avocado")
Text("Avocado Toast")}.lineLimit(1)Delicious

Avocado T…

How Stacks Work

HStack {Text("Delicious")
Image("20x20_avocado")
Text("Avocado Toast")}.lineLimit(1)Deli…

Avocado…

How Stacks Work

HStack {Text("Delicious")
Image("20x20_avocado")
Text("Avocado Toast")}.lineLimit(1)…

Avocado Toast

Layout Priority

HStack {Text("Delicious")
Image("20x20_avocado")
Text("Avocado Toast").layoutPriority(1)}.lineLimit(1)…

Avocado Toast

Layout Priority
w₀+w₁
HStack {Text("Delicious")
Image("20x20_avocado")
Text("Avocado Toast").layoutPriority(1)}.lineLimit(1)w₀…

Avocado Toast
w₁

Alignments

HStack(alignment: .center) {Text("Delicious")
Image("20x20_avocado")
Text("Avocado Toast").layoutPriority(1)}.lineLimit(1)Delicious

Avocado Toast

Alignments

HStack(alignment: .bottom) {Text("Delicious")
Image("20x20_avocado")
Text("Avocado Toast").layoutPriority(1)}.lineLimit(1)Delicious

Avocado Toast

Alignments

HStack(alignment: .bottom) {Text("Delicious").font(.caption)
Image("20x20_avocado")
Text("Avocado Toast").layoutPriority(1)}.lineLimit(1)Delicious

Avocado Toast

Alignments

HStack(alignment: .bottom) {Text("Delicious").font(.caption)
Image("20x20_avocado")
Text("Avocado Toast").layoutPriority(1)}.lineLimit(1)Delicious

Avocado Toast

Alignments

HStack(alignment: .bottom) {Text("Delicious").font(.caption)
Image("20x20_avocado")
Text("Avocado Toast").layoutPriority(1)}.lineLimit(1)Delicious

Avocado Toast

Alignments

HStack(alignment: .bottom) {Text("Delicious").font(.caption)
Image("20x20_avocado")
Text("Avocado Toast").layoutPriority(1)}.lineLimit(1)Delicious

Avocado Toast

Alignments

HStack(alignment: .bottom) {Text("Delicious").font(.caption)
Image("20x20_avocado")
Text("Avocado Toast").layoutPriority(1)}.lineLimit(1)Delicious

Avocado Toast

Alignments

HStack(alignment: .bottom) {Text("Delicious").font(.caption)
Image("20x20_avocado")
Text("Avocado Toast").layoutPriority(1)}.lineLimit(1)Delicious

Avocado Toast

Alignments

HStack(alignment: .bottom) {Text("Delicious").font(.caption)
Image("20x20_avocado")
Text("Avocado Toast").layoutPriority(1)}.lineLimit(1)Delicious

Avocado Toast

Alignments

HStack(alignment: .lastTextBaseline) {Text("Delicious").font(.caption)
Image("20x20_avocado")
Text("Avocado Toast").layoutPriority(1)}.lineLimit(1)Delicious

Avocado Toast

Alignments

HStack(alignment: .lastTextBaseline) {Text("Delicious").font(.caption)
Image("20x20_avocado")
Text("Avocado Toast").layoutPriority(1)}.lineLimit(1)Delicious

Avocado Toast

Alignments

HStack(alignment: .lastTextBaseline) {Text("Delicious").font(.caption)
Image("20x20_avocado")
Text("Avocado Toast").layoutPriority(1)}.lineLimit(1)87.4%

Delicious

Avocado Toast

Alignments

HStack(alignment: .lastTextBaseline) {Text("Delicious").font(.caption)
Image("20x20_avocado").alignmentGuide(.lastTextBaseline) { d in d[.bottom] * 0.927 }Text("Avocado Toast").layoutPriority(1)}.lineLimit(1)87.4%

Delicious

Avocado Toast

Alignments

HStack(alignment: .lastTextBaseline) {Text("Delicious").font(.caption)
Image("20x20_avocado").alignmentGuide(.lastTextBaseline) { d in d[.bottom] * 0.927 }Text("Avocado Toast").layoutPriority(1)}.lineLimit(1)87.4%

Delicious

Avocado Toast

Alignments★★★★★
5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

Alignments★★★★★
5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

Alignments★★★★★
5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

Alignments★★★★★

Avocado Toast

5 stars

Ingredients: Avocado, Almond Butter, Bread, Red Pep…

HStack {★★★★★

VStack {Text("★★★★★")

5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

Text("5 stars")}.font(.caption)
VStack(alignment: .leading) {HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack(alignment: .center) {VStack {★★★★★

Text("★★★★★")

5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

Text("5 stars")}.font(.caption)
VStack(alignment: .leading) {HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}Defining a New Vertical Alignment

extension VerticalAlignment {private enum MidStarAndTitle : AlignmentID {static func defaultValue(in d: ViewDimensions) -> Length {return d[.bottom]}}
static let midStarAndTitle = VerticalAlignment(MidStarAndTitle.self)}

Defining a New Vertical Alignment

extension VerticalAlignment {private enum MidStarAndTitle : AlignmentID {static func defaultValue(in d: ViewDimensions) -> Length {return d[.bottom]}}
static let midStarAndTitle = VerticalAlignment(MidStarAndTitle.self)}

Defining a New Vertical Alignment

extension VerticalAlignment {private enum MidStarAndTitle : AlignmentID {static func defaultValue(in d: ViewDimensions) -> Length {return d[.bottom]}}
static let midStarAndTitle = VerticalAlignment(MidStarAndTitle.self)}

Defining a New Vertical Alignment

extension VerticalAlignment {private enum MidStarAndTitle : AlignmentID {static func defaultValue(in d: ViewDimensions) -> Length {return d[.bottom]}}
static let midStarAndTitle = VerticalAlignment(MidStarAndTitle.self)}

Defining a New Vertical Alignment

extension VerticalAlignment {private enum MidStarAndTitle : AlignmentID {static func defaultValue(in d: ViewDimensions) -> Length {return d[.bottom]}}
static let midStarAndTitle = VerticalAlignment(MidStarAndTitle.self)}

Defining a New Vertical Alignment

extension VerticalAlignment {private enum MidStarAndTitle : AlignmentID {static func defaultValue(in d: ViewDimensions) -> Length {return d[.bottom]}}
static let midStarAndTitle = VerticalAlignment(MidStarAndTitle.self)}HStack(alignment: .midStarAndTitle) {VStack {★★★★★

Text("★★★★★")

5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

Text("5 stars")}.font(.caption)
VStack(alignment: .leading) {HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack(alignment: .midStarAndTitle) {VStack {★★★★★

Text("★★★★★")

5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

Text("5 stars")}.font(.caption)
VStack(alignment: .leading) {HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack(alignment: .midStarAndTitle) {VStack {★★★★★

Text("★★★★★")

5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

.alignmentGuide(.midStarAndTitle) { d in d[.bottom] / 2 }Text("5 stars")}.font(.caption)
VStack(alignment: .leading) {HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack(alignment: .midStarAndTitle) {VStack {★★★★★

Text("★★★★★")

5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

.alignmentGuide(.midStarAndTitle) { d in d[.bottom] / 2 }Text("5 stars")}.font(.caption)
VStack(alignment: .leading) {HStack {Text("Avocado Toast").font(.title)
Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack(alignment: .midStarAndTitle) {VStack {★★★★★

Text("★★★★★")

5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

.alignmentGuide(.midStarAndTitle) { d in d[.bottom] / 2 }Text("5 stars")}.font(.caption)
VStack(alignment: .leading) {HStack {Text("Avocado Toast").font(.title).alignmentGuide(.midStarAndTitle) { d in d[.bottom] / 2 }Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack(alignment: .midStarAndTitle) {VStack {★★★★★

Text("★★★★★")

5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

.alignmentGuide(.midStarAndTitle) { d in d[.bottom] / 2 }Text("5 stars")}.font(.caption)
VStack(alignment: .leading) {HStack {Text("Avocado Toast").font(.title).alignmentGuide(.midStarAndTitle) { d in d[.bottom] / 2 }Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}HStack(alignment: .midStarAndTitle) {VStack {★★★★★

Text("★★★★★")

5 stars

Avocado Toast
Ingredients: Avocado, Almond Butter, Bread, Red Pep…

.alignmentGuide(.midStarAndTitle) { d in d[.bottom] / 2 }Text("5 stars")}.font(.caption)
VStack(alignment: .leading) {HStack {Text("Avocado Toast").font(.title).alignmentGuide(.midStarAndTitle) { d in d[.bottom] / 2 }Spacer()Image("20x20_avocado")}
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes").font(.caption).lineLimit(1)}}•Graphics in SwiftUIJohn Harper

First Steps

struct RedCircle: View {var body: some View {}}First Steps

struct RedCircle: View {var body: some View {// return a filled circle.
Circle().fill(Color.red)}}

First Steps

struct RedCircle: View {var body: some View {// return a filled circle.
Circle().fill(Color.red)}}

Drawing ↔ Views

Drawing Model
shape.op(style) → view

Circle()Capsule()Ellipse()Drawing Model
shape.op(style) → view

Circle().fill(red)Capsule()Ellipse()Drawing Model
shape.op(style) → view

Circle().fill(…)

Capsule().stroke(red, lineWidth: 20)

Ellipse()Drawing Model
shape.op(style) → view

Circle().fill(…)

Capsule().stroke(…)

Ellipse().strokeBorder(red, style: …)

Shape Styles

Styles are ways of making a view from a shape• Colors• Tiled images• Gradients: Linear, radial, angular (conic)

Gradients

struct GradientView: View {var body: some View {let spectrum = Gradient(colors: [.red, .yellow, .green, .cyan, .blue, .purple, .red
])
0

}
}

1

Gradients

struct GradientView: View {var body: some View {let spectrum = Gradient(colors: [.red, .yellow, .green, .cyan, .blue, .purple, .red])
let conic = AngularGradient(gradient: spectrum,
center: .center, angle: .degrees(-90))

}
}

1

0
-90°

Gradients

struct GradientView: View {var body: some View {let spectrum = Gradient(colors: [.red, .yellow, .green, .cyan, .blue, .purple, .red])
let conic = AngularGradient(gradient: spectrum,
center: .center, angle: .degrees(-90))
return Circle().fill(conic)}}

Gradients

struct GradientView: View {var body: some View {let spectrum = Gradient(colors: [.red, .yellow, .green, .cyan, .blue, .purple, .red])
let conic = AngularGradient(gradient: spectrum,
center: .center, angle: .degrees(-90))
return Circle().strokeBorder(conic, lineWidth: 50)}}

Sample Control

Sample Control

Sample Control
width// Data model.
class Ring {struct Wedge {var width: Double
var depth: Double
var hue: Double}
var wedges: [Int: Wedge]
var wedgeIDs: [Int]
}

depth

Sample Control

Sample Control

Sample Control

struct WedgeShape: Shape {var wedge: Ring.Wedge
func path(in rect: CGRect) -> Path {var p = Path()

return p
}
}

r1
a1°
r0

struct WedgeShape: Shape {var wedge: Ring.Wedge
func path(in rect: CGRect) -> Path {var p = Path()
let g = WedgeGeometry(wedge, in: rect)

return p
}
}

a0°
cen

0°

struct WedgeShape: Shape {var wedge: Ring.Wedge
func path(in rect: CGRect) -> Path {var p = Path()
let g = WedgeGeometry(wedge, in: rect)
p.addArc(center: g.cen, radius: g.r0, startAngle: g.a0, endAngle: g.a1, clockwise: false)

return p}}

struct WedgeShape: Shape {var wedge: Ring.Wedge
func path(in rect: CGRect) -> Path {var p = Path()
let g = WedgeGeometry(wedge, in: rect)
p.addArc(center: g.cen, radius: g.r0, startAngle: g.a0, endAngle: g.a1, clockwise: false)

return p}}

struct WedgeShape: Shape {var wedge: Ring.Wedge
func path(in rect: CGRect) -> Path {var p = Path()
let g = WedgeGeometry(wedge, in: rect)
p.addArc(center: g.cen, radius: g.r0, startAngle: g.a0, endAngle: g.a1, clockwise: false)
p.addLine(to: g.topRight)

return p}}

struct WedgeShape: Shape {var wedge: Ring.Wedge
func path(in rect: CGRect) -> Path {var p = Path()
let g = WedgeGeometry(wedge, in: rect)
p.addArc(center: g.cen, radius: g.r0, startAngle: g.a0, endAngle: g.a1, clockwise: false)
p.addLine(to: g.topRight)

return p}}

struct WedgeShape: Shape {var wedge: Ring.Wedge
func path(in rect: CGRect) -> Path {var p = Path()
let g = WedgeGeometry(wedge, in: rect)
p.addArc(center: g.cen, radius: g.r0, startAngle: g.a0, endAngle: g.a1, clockwise: false)
p.addLine(to: g.topRight)
p.addArc(center: g.cen, radius: g.r1, startAngle: g.a1, endAngle: g.a0, clockwise: true)
return p}}

struct WedgeShape: Shape {var wedge: Ring.Wedge
func path(in rect: CGRect) -> Path {var p = Path()
let g = WedgeGeometry(wedge, in: rect)
p.addArc(center: g.cen, radius: g.r0, startAngle: g.a0, endAngle: g.a1, clockwise: false)
p.addLine(to: g.topRight)
p.addArc(center: g.cen, radius: g.r1, startAngle: g.a1, endAngle: g.a0, clockwise: true)
return p}}

struct WedgeShape: Shape {var wedge: Ring.Wedge
func path(in rect: CGRect) -> Path {var p = Path()
let g = WedgeGeometry(wedge, in: rect)
p.addArc(center: g.cen, radius: g.r0, startAngle: g.a0, endAngle: g.a1, clockwise: false)
p.addLine(to: g.topRight)
p.addArc(center: g.cen, radius: g.r1, startAngle: g.a1, endAngle: g.a0, clockwise: true)
p.closeSubpath()
return p}}

struct WedgeShape: Shape {var wedge: Ring.Wedge
func path(in rect: CGRect) -> Path {var p = Path()
let g = WedgeGeometry(wedge, in: rect)
p.addArc(center: g.cen, radius: g.r0, startAngle: g.a0, endAngle: g.a1, clockwise: false)
p.addLine(to: g.topRight)
p.addArc(center: g.cen, radius: g.r1, startAngle: g.a1, endAngle: g.a0, clockwise: true)
p.closeSubpath()
return p}}

struct WedgeShape: Shape {var wedge: Ring.Wedge
func path(in rect: CGRect) -> Path { … }var animatableData: … {}}struct WedgeShape: Shape {var wedge: Ring.Wedge
func path(in rect: CGRect) -> Path { … }var animatableData: Ring.Wedge.AnimatableData {get { return wedge.animatableData }set { wedge.animatableData = newValue }}}Multi-Part Drawing

Multi-Part Drawing

Multi-Part Drawing

struct RingView: View {@EnvironmentObject var ring: Ringvar body: some View {ZStack {}}}struct RingView: View {@EnvironmentObject var ring: Ringvar body: some View {ZStack {ForEach(ring.wedgeIDs) { id in
WedgeView(self.ring.wedges[id]!)

}
}
}
}

struct RingView: View {@EnvironmentObject var ring: Ringvar body: some View {ZStack {ForEach(ring.wedgeIDs) { id in
WedgeView(self.ring.wedges[id]!).tapAction { withAnimation { self.ring.deleteWedge(id: id) } }}}}}struct RingView: View {@EnvironmentObject var ring: Ringvar body: some View {ZStack {ForEach(ring.wedgeIDs) { id in
WedgeView(self.ring.wedges[id]!).tapAction { withAnimation { self.ring.deleteWedge(id: id) } }.transition(scaleAndFade)}}}}Custom Transitions

View Inserted

View Idle

View Removed

Custom Transitions

View Inserted
Animation

View Idle

Animation

View Removed

Custom Transitions
isActive: true

isActive: falseisActive: true

struct ScaleAndFade: ViewModifier {var isActive: Boolfunc body(content: Content) -> some View {return content}}

isActive: falseisActive: true

isActive: false

struct ScaleAndFade: ViewModifier {var isActive: Boolfunc body(content: Content) -> some View {return content}}.scaleEffect(isActive ? 0.1 : 1)// scale: 10% or 100%

.opacity(isActive ? 0 : 1)// opacity: 0% or 100%

isActive: true

struct ScaleAndFade: ViewModifier {var isActive: Boolfunc body(content: Content) -> some View { … }}let scaleAndFade = AnyTransition.modifier(active: ScaleAndFade(isActive: true),
identity: ScaleAndFade(isActive: false))

isActive: false

•

Demo

Graphic Effects

Opacity
Geometry (scales, rotations, etc.)
Color effects (contrast, brightness, hue rotate, monochrome, etc.)
Blur effectDrop shadow effectClipping, masking
Compositing, groups, blend modes

SwiftUI’s Unified ModelAll customization centers on View
• Layout• Graphics• Animation and transitions• Interaction

Combine these to produce delightful results!

More Information
developer.apple.com/wwdc19/237

SwiftUI Lab

Friday, 11:00