building custom views in swiftui - apple inc. · layout procedure 1. parent proposes a size for...
TRANSCRIPT
#WWDC19
© 2019 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple.
Dave Abrahams John Harper
•Building Custom Views in SwiftUI •Graphic effects and layout
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
Text
ContentView
Layout Basics
struct ContentView : View { var body: some View { Text("Hello World") } } Hello World
Text
ContentView
Root View
Layout Basics
struct ContentView : View { var body: some View { Text("Hello World") } } Hello World
Text
ContentView
Root View
Layout Basics
struct ContentView : View { var body: some View { Text("Hello World") .edgesIgnoringSafeArea(.all) } }
Hello World
Text
ContentView
Root View
Layout Basics
struct ContentView : View { var body: some View { Text("Hello World") } }
ContentView
Text
Root View
Hello World
Layout Basics
struct ContentView : View { var body: some View { Text("Hello World") } }
ContentView
Text
Root View
Hello World
Layout Basics
struct ContentView : View { var body: some View { Text("Hello World") } }
ContentViewText
Root View
Hello World
1. Parent Proposes Size for Child
struct ContentView : View { var body: some View { Text("Hello World") } }
ContentViewText
Root View
Hello World
2. Child Chooses Its Own Size
struct ContentView : View { var body: some View { Text("Hello World") } }
ContentViewText
Root View
3. Parent Places Child in Parent’s Coordinate Space
struct ContentView : View { var body: some View { Text("Hello World") } }
ContentViewText
Root View
Hello World
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 child 2. Child chooses its own size 3. Parent places child in parent’s coordinate space
struct TrippyBadge : View { var body: some View { Image("ColorWash") .frame(width: 50, height: 10) } }
Child chooses its own size
Resizable Image
Frame
10
50
Layout Procedure
1. Parent proposes a size for child 2. Child chooses its own size 3. Parent places child in parent’s coordinate space
struct TrippyBadge : View { var body: some View { Image("ColorWash") .frame(width: 50, height: 10) } }
Child chooses its own size
Resizable Image
Frame
10
50
Layout Procedure
1. Parent proposes a size for child 2. Child chooses its own size 3. Parent places child in parent’s coordinate space
struct WedgeChart : View { var body: some View { Image("Wedges") .aspectRatio(1) } }
Child chooses its own size
Resizable Image
Aspect Ratio View
Layout Procedure
1. Parent proposes a size for child 2. Child chooses its own size 3. Parent places child in parent’s coordinate space
struct WedgeChart : View { var body: some View { Image("Wedges") .aspectRatio(1) } }
Child chooses its own size
Resizable Image
Aspect Ratio View
Layout Procedure
1. Parent proposes a size for child 2. Child chooses its own size 3. Parent places child in parent’s coordinate space
struct ContentView : View { var body: some View { Text("Hello World") } }
Child chooses its own size
Text
Root View
Hello World
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") } } Hello World
Text
Root View
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") } } Avocado Toast
Text
Root View
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") .background(Color.green) } }
Avocado Toast
Text
Root View
Background
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") .background(Color.green) } }
Avocado Toast
Text
Root View
Background
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") .background(Color.green) } }
Avocado Toast
ColorText
Root View
Background
Delicious Avocado Toast
Avocado Toast
Padding ColorText
Root View
Background
struct Toast : View { var body: some View { Text("Avocado Toast") .padding() .background(Color.green) } }
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") .padding() .background(Color.green) } }
Avocado Toast
Padding Color
Text
Root View
Background
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") .padding([.leading, .trailing]) .background(Color.green) } }
Avocado Toast
Padding Color
Text
Root View
Background
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") .padding(10) .background(Color.green) } }
Avocado Toast
Padding Color
Text
Root View
Background
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") .padding(10) .background(Color.green) } }
Avocado Toast
Padding Color
Text
Root View
Background
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") .padding(10) .background(Color.green) } }
Padding Color
Text
Root View
Background
Avocado Toast
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") .padding(10) .background(Color.green) } }
Padding Color
Text
Root View
Background
Avocado Toast
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") .padding(10) .background(Color.green) } }
Padding Color
Text
Root View
Background
Avocado Toast
10
10
10
10
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") .padding(10) .background(Color.green) } }
Padding Color
Text
Root View
Background
Avocado Toast
10
10
10
10
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") .padding(10) .background(Color.green) } }
Padding Color
Text
Root View
Background
Avocado Toast
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") .padding(10) .background(Color.green) } }
Padding Color
Text
Root View
Background
Avocado Toast
10
10 10
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") .padding(10) .background(Color.green) } }
Padding Color
Text
Root View
Background
Avocado Toast
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") .padding(10) .background(Color.green) } }
Padding Color
Text
Root View
Background
Avocado Toast
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") .padding(10) .background(Color.green) } }
Padding Color
Text
Root View
Background
Avocado Toast
Delicious Avocado Toast
struct Toast : View { var body: some View { Text("Avocado Toast") .padding(10) .background(Color.green) } }
Padding Color
Text
Root View
Background
Avocado Toast
Scrumptious Avocado
struct Avocado : View { var body: some View { Image("20x20_avocado") } } 20
20
Image
Root View
Scrumptious Avocado
struct Avocado : View { var body: some View { Image("20x20_avocado") } } 20
20
Frame Image
Root View
Scrumptious Avocado
struct Avocado : View { var body: some View { Image("20x20_avocado") .frame(width: 30, height: 30) } }
Frame
Image
Root View20
20
Scrumptious Avocado
struct Avocado : View { var body: some View { Image("20x20_avocado") .frame(width: 30, height: 30) } }
Frame
Image
Root View30
30
•This Is as It Should Be There’s no wrong way to do it
HStack and VStack
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack { VStack { Text("★★★★★") 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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack { VStack { Text("★★★★★") 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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★HStack { VStack { Text("★★★★★") 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)
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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack { VStack { Text("★★★★★") 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) } }
5 stars
★★★★★
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast
HStack { VStack { Text("★★★★★") 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)
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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack { VStack { Text("★★★★★") 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)
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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack { VStack { Text("★★★★★") 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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack { VStack { Text("★★★★★") 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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack { VStack { Text("★★★★★") 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)
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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack { VStack { Text("★★★★★") 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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast 🥑 5 stars
★★★★★
HStack { VStack { Text("★★★★★") 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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast 🥑 5 stars
★★★★★
HStack { VStack { Text("★★★★★") 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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…5 stars
★★★★★ Avocado Toast
HStack { VStack { Text("★★★★★") 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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…5 stars
★★★★★
HStack { VStack { Text("★★★★★") Text("5 stars") }.font(.caption)
VStack(alignment: .leading) {
Text("Avocado Toast").font(.title) Spacer() Image("20x20_avocado") }
Text("Ingredients: Avocado, Almond Butter, Bread, Red Pepper Flakes") .font(.caption).lineLimit(1) } }
Avocado Toast
HStack { VStack { Text("★★★★★") 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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast
5 stars
★★★★★
HStack { VStack { Text("★★★★★") 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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast
5 stars
★★★★★
HStack { VStack { Text("★★★★★") 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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast
5 stars
★★★★★
HStack { VStack { Text("★★★★★") 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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast
5 stars
★★★★★
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast
HStack and VStack
5 stars
★★★★★
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast
HStack and VStack
5 stars
★★★★★
HStack and VStack
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack and VStack
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack and VStack
VStack { ListCell() Toggle(isOn: $on) { ... } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack and VStack
VStack { ListCell() Toggle(isOn: $on) { ... } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack and VStack
VStack(spacing: 4) { ListCell() Toggle(isOn: $on) { ... } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack and VStack
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack and VStack
خبزة محمصة معنجوم 5
★★★★★
المكونات: أفوكادو، زبدة لوز، خبر، رقائق فلفل أحمر
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
Delicious Avocado Toast
Parent
HStack
Text TextImage
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
Delicious Avocado Toast
Parent
HStack
Text TextImage
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1) Parent
HStack
Text TextImage
Delicious Avocado Toast
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1) Parent
HStack
Text TextImage
Deli… Avocado…
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
Delicious Avocado Toast
Parent
HStack
Text TextImage
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
Delicious Avocado ToastS₀ S₁
Parent
HStack
Text TextImage
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
Delicious Avocado Toast
S₀ + S₁
Parent
HStack
Text TextImage
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
Delicious Avocado Toast
Parent
HStack
Text TextImage
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
Delicious Avocado Toast
Parent
HStack
Text TextImage
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
Delicious Avocado Toast
Parent
HStack
Text TextImage
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1) Parent
HStack
Text TextImage
How Stacks Work
Delicious Avocado Toast
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1) Parent
HStack
Text TextImage
How Stacks Work
Delicious Avocado Toast
w
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1) Parent
HStack
Text TextImage
Delicious Avocado Toast
w
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1) Parent
HStack
Text TextImage
Delicious Avocado Toast
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
Delicious Avocado Toast
Parent
HStack
Text TextImage
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
Delicious Avocado Toast
Parent
HStack
Text TextImage
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
Delicious Avocado Toastw
Parent
HStack
Text TextImage
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1) Parent
HStack
Text TextImage
How Stacks Work
Delicious Avocado Toast
w
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1) Parent
HStack
Text TextImage
How Stacks Work
Delicious Avocado Toast
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
How Stacks Work
Parent
HStack
Text TextImage
Delicious Avocado Toast
Parent
HStack
Text TextImage
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
Delicious Avocado Toast
Parent
HStack
Text TextImage
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
S₀ S₁
Delicious Avocado Toast
Parent
HStack
Text TextImage
How Stacks Work
HStack(alignment: .center) { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
Delicious Avocado Toast
Parent
HStack
Text TextImage
How Stacks Work
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
Delicious Avocado Toast
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
How Stacks Work
Delicious Avocado T…
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast") } .lineLimit(1)
How Stacks Work
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
HStack { Text("Delicious") Image("20x20_avocado") Text("Avocado Toast").layoutPriority(1) } .lineLimit(1)
… Avocado Toast
w₀+w₁
w₀
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)
Avocado ToastDelicious
HStack(alignment: .bottom) { Text("Delicious").font(.caption) Image("20x20_avocado") Text("Avocado Toast").layoutPriority(1) } .lineLimit(1)
Alignments
Avocado ToastDelicious
HStack(alignment: .bottom) { Text("Delicious").font(.caption) Image("20x20_avocado") Text("Avocado Toast").layoutPriority(1) } .lineLimit(1)
Alignments
Avocado ToastDelicious
HStack(alignment: .bottom) { Text("Delicious").font(.caption) Image("20x20_avocado") Text("Avocado Toast").layoutPriority(1) } .lineLimit(1)
Alignments
Avocado ToastDelicious
HStack(alignment: .bottom) { Text("Delicious").font(.caption) Image("20x20_avocado") Text("Avocado Toast").layoutPriority(1) } .lineLimit(1)
Alignments
Avocado ToastDelicious
HStack(alignment: .bottom) { Text("Delicious").font(.caption) Image("20x20_avocado") Text("Avocado Toast").layoutPriority(1) } .lineLimit(1)
Alignments
Avocado ToastDelicious
HStack(alignment: .bottom) { Text("Delicious").font(.caption) Image("20x20_avocado") Text("Avocado Toast").layoutPriority(1) } .lineLimit(1)
Alignments
Avocado ToastDelicious
HStack(alignment: .lastTextBaseline) { Text("Delicious").font(.caption) Image("20x20_avocado") Text("Avocado Toast").layoutPriority(1) } .lineLimit(1)
Alignments
Avocado ToastDelicious
HStack(alignment: .lastTextBaseline) { Text("Delicious").font(.caption) Image("20x20_avocado") Text("Avocado Toast").layoutPriority(1) } .lineLimit(1)
Alignments
Avocado ToastDelicious
HStack(alignment: .lastTextBaseline) { Text("Delicious").font(.caption) Image("20x20_avocado") Text("Avocado Toast").layoutPriority(1) } .lineLimit(1)
Alignments
Avocado ToastDelicious
87.4%
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)
Alignments
Avocado ToastDelicious
87.4%
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)
Alignments
Avocado ToastDelicious
87.4%
Alignments
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
Alignments
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
Alignments
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
Alignments
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack { VStack { Text("★★★★★") 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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack(alignment: .center) { VStack { Text("★★★★★") 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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
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) }
Defining a New Vertical Alignment
HStack(alignment: .midStarAndTitle) { VStack { Text("★★★★★") 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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack(alignment: .midStarAndTitle) { VStack { Text("★★★★★") 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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack(alignment: .midStarAndTitle) { VStack { Text("★★★★★") .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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack(alignment: .midStarAndTitle) { VStack { Text("★★★★★") .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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack(alignment: .midStarAndTitle) { VStack { Text("★★★★★") .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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack(alignment: .midStarAndTitle) { VStack { Text("★★★★★") .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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
HStack(alignment: .midStarAndTitle) { VStack { Text("★★★★★") .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) } }
Ingredients: Avocado, Almond Butter, Bread, Red Pep…
Avocado Toast5 stars
★★★★★
John Harper
•Graphics in SwiftUI
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) } }
First Steps
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))
} }
01
-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
depth
// Data model. class Ring { struct Wedge { var width: Double var depth: Double var hue: Double }
var wedges: [Int: Wedge] var wedgeIDs: [Int] }
Sample Control
Sample Control
Sample Control
struct WedgeShape: Shape { var wedge: Ring.Wedge
func path(in rect: CGRect) -> Path { var p = Path()
return p } }
struct WedgeShape: Shape { var wedge: Ring.Wedge
func path(in rect: CGRect) -> Path { var p = Path() let g = WedgeGeometry(wedge, in: rect)
return p } }
cena0°
a1°
r0
r1
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: Ring
var body: some View { ZStack {
} } }
struct RingView: View { @EnvironmentObject var ring: Ring
var body: some View { ZStack { ForEach(ring.wedgeIDs) { id in WedgeView(self.ring.wedges[id]!)
} } } }
struct RingView: View { @EnvironmentObject var ring: Ring
var 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: Ring
var 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 Removed
View Idle
Custom Transitions
Animation
Animation
View Inserted
View Removed
View Idle
Custom Transitions
isActive: true
isActive: false
struct ScaleAndFade: ViewModifier { var isActive: Bool
func body(content: Content) -> some View { return content
} }
isActive: true
isActive: false
struct ScaleAndFade: ViewModifier { var isActive: Bool
func 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
isActive: false
struct ScaleAndFade: ViewModifier { var isActive: Bool
func body(content: Content) -> some View { … } }
let scaleAndFade = AnyTransition.modifier( active: ScaleAndFade(isActive: true), identity: ScaleAndFade(isActive: false))
isActive: true
isActive: false
•Demo
Graphic Effects
Opacity
Geometry (scales, rotations, etc.)
Color effects (contrast, brightness, hue rotate, monochrome, etc.)
Blur effect
Drop shadow effect
Clipping, masking
Compositing, groups, blend modes
SwiftUI’s Unified Model
All customization centers on View • Layout • Graphics • Animation and transitions • Interaction
Combine these to produce delightful results!
More Informationdeveloper.apple.com/wwdc19/237
SwiftUI Lab Friday, 11:00