Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
入門 SwiftUI Alignment Guide / iOSDC2022
Search
monoqlo
September 11, 2022
Technology
11
5.1k
入門 SwiftUI Alignment Guide / iOSDC2022
iOSDC Japan 2022 2022/09/11
monoqlo
September 11, 2022
Tweet
Share
More Decks by monoqlo
See All by monoqlo
Hey Siri!マルチプラットフォームでのSiriショートカットの地雷を教えて / iOSDC2021
monoqlo
0
670
あなたのアプリ、✨リブランディング✨できますか? / iosdc2020
monoqlo
9
1.5k
実践 CallKit/PushKit ときどき🐛退治 / iOSDC 2019
monoqlo
4
3.6k
「QRコード読み取り?楽勝ですよ😙」=>「AVFoundationを信じたおれがバカだった😇」 / iOSDC 2018
monoqlo
10
26k
WWDC2016のススメ
monoqlo
0
100
Other Decks in Technology
See All in Technology
JAWS FESTA 2024「バスロケ」GPS×サーバーレスの開発と運用の舞台裏/jawsfesta2024-bus-gps-serverless
ma2shita
3
290
E2Eテスト自動化入門
devops_vtj
1
110
目標と時間軸 〜ベイビーステップでケイパビリティを高めよう〜
kakehashi
PRO
8
900
開発者のための FinOps/FinOps for Engineers
oracle4engineer
PRO
2
220
IAMのマニアックな話2025
nrinetcom
PRO
6
1.4k
OPENLOGI Company Profile
hr01
0
60k
Exadata Database Service on Cloud@Customer セキュリティ、ネットワーク、および管理について
oracle4engineer
PRO
2
1.6k
1行のコードから社会課題の解決へ: EMの探究、事業・技術・組織を紡ぐ実践知 / EM Conf 2025
9ma3r
12
4.5k
JavaにおけるNull非許容性
skrb
2
2.7k
30→150人のエンジニア組織拡大に伴うアジャイル文化を醸成する役割と取り組みの変化
nagata03
0
240
いまからでも遅くない!コンテナでWebアプリを動かしてみよう!コンテナハンズオン編
nomu
0
170
Introduction to OpenSearch Project - Search Engineering Tech Talk 2025 Winter
tkykenmt
2
160
Featured
See All Featured
The Art of Programming - Codeland 2020
erikaheidi
53
13k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
27
1.9k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
The Invisible Side of Design
smashingmag
299
50k
The Cult of Friendly URLs
andyhume
78
6.2k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
6
580
4 Signs Your Business is Dying
shpigford
183
22k
Being A Developer After 40
akosma
89
590k
RailsConf 2023
tenderlove
29
1k
Building Your Own Lightsaber
phodgson
104
6.2k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.2k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.3k
Transcript
@monoqloʢͷ͘Ζʣ ೖSwiftUI Alignment Guide iOSDC Japan 2022
͡Ίʹ
• ʮೖʯͱ͋ΔΑ͏ʹϝΠϯλʔήοτSwiftUIॳ৺ऀͰ͢ • ۩ମతʹŋŋŋ • alignmentGuide(_:computeValue:) ͬͨ͜ͱͳ͍ • Custom Alignment
Guideͬͨ͜ͱͳ͍ • ͬͨ͜ͱ͋Δ͚ͲΑ͘Θ͔Βͳ͔ͬͨ ॳ৺ऀ͚ͷτʔΫͰ͢
• 2,3લ͔ͬ͢Β͔ΜͩͬͨެࣜυΩϡϝϯτ… • ͍ͭͷ·ʹ͔େॆ࣮ • ࠷ֶۙͼ࢝ΊͨਓٯʹΑ͍ͬͯ͘ΔՄೳੑ😇 • ਖ਼͜ͷτʔΫͷඞཁੑΛٙ͏΄ͲΊͪΌͪ͘Όྑ͍ࢿྉ • ͔͍ͭ·ΜͰҾ༻ͭͭ͠ղઆ
• εϥΠυͷ࠷ޙʹࢀߟจݙͱͯ͠URLهࡌ ࠷ۙͷެࣜυΩϡϝϯτେॆ࣮
ୈষ Alignment Guideͱ
ྫ
HStack { VStack { Rectangle() .fill(.blue) .frame(width: 100, height: 400)
Text("Long Blue Bar") .font(.title) } VStack { Rectangle() .fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar") .font(.title) Text("iOSDC 2022 sample code #1") .font(.caption) } }
None
ղྫ
HStack { VStack { Rectangle() .fill(.blue) .frame(width: 100, height: 400)
Text("Long Blue Bar") .font(.title) } VStack { Rectangle() .fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar") .font(.title) Text("iOSDC 2022 sample code #1") .font(.caption) } }
HStack(alignment: .bottom) { VStack { Rectangle() .fill(.blue) .frame(width: 100, height:
400) Text("Long Blue Bar") .font(.title) } VStack { Rectangle() .fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar") .font(.title) Text("iOSDC 2022 sample code #1") .font(.caption) } }
ղઆ
VStack { Text("Hello,") Text("😺🐶🐢🐰🐳") Text("Animals!") }
VStack { Text("Hello,") Text("😺🐶🐢🐰🐳") Text("Animals!") }
VStack { Color.white.frame(width: 1) Text("Hello,") Text("😺🐶🐢🐰🐳") Text(“Animals!") Color.white.frame(width: 1) }
VStack(alignment: .center) { Color.white.frame(width: 1) Text("Hello,") Text("😺🐶🐢🐰🐳") Text(“Animals!") Color.white.frame(width: 1)
}
VStack(alignment: .leading) { Color.white.frame(width: 1) Text("Hello,") Text("😺🐶🐢🐰🐳") Text(“Animals!") Color.white.frame(width: 1)
}
VStack(alignment: .leading) { Color.white.frame(width: 1) Text("Hello,") Text("😺🐶🐢🐰🐳") Text(“Animals!") Color.white.frame(width: 1)
} .environment(\.layoutDirection, .rightToLeft)
Built-in Alignment Guides
HorizontalAlignment • leading • center • trailing • listRowSeparatorLeading •
listRowSeparatorTrailing Built-in Alignment Guides VerticalAlignment • top • center • bottom • fi rstTextBaseline • lastTextBaseline
HorizontalAlignment • leading • center • trailing • (listRowSeparatorLeading) •
(listRowSeparatorTrailing) Built-in Alignment Guides
VerticalAlignment • top • center • bottom • fi rstTextBaseline
• lastTextBaseline Built-in Alignment Guides
Alignment HorizontalAlignment × VerticalAlignment Built-in Alignment Guides https://developer.apple.com/documentation/swiftui/alignment
Built-in Alignment Guides
Custom Alignment Guide
ୈষ alignmentGuide(_:computeValue:)
ྫ
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } Color.white.frame(width: 1) }
None
None
ղྫ
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) ForEach(["Dog", "Crocodile", “Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } Color.white.frame(width: 1) }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } .alignmentGuide(.trailing) { context in context.width * 2 } Color.white.frame(width: 1) }
ղઆ
alignmentGuide(_:computeValue:)
func alignmentGuide( _ g: HorizontalAlignment, computeValue: @escaping (ViewDimensions) -> CGFloat
) -> some View alignmentGuide(_:computeValue:) func alignmentGuide( _ g: VerticalAlignment, computeValue: @escaping (ViewDimensions) -> CGFloat ) -> some View https://developer.apple.com/documentation/swiftui/view/alignmentguide(_:computevalue:)-6y3u2 https://developer.apple.com/documentation/swiftui/view/alignmentguide(_:computevalue:)-9mdoh
func alignmentGuide( _ g: HorizontalAlignment, computeValue: @escaping (ViewDimensions) -> CGFloat
) -> some View alignmentGuide(_:computeValue:) • ج४ͱͳΔAlignment͔ΒͷҐஔΛௐͰ͖ΔViewModi fi er
func alignmentGuide( _ g: HorizontalAlignment, computeValue: @escaping (ViewDimensions) -> CGFloat
) -> some View alignmentGuide(_:computeValue:) • ج४ͱͳΔAlignment͔ΒͷҐஔΛௐͰ͖ΔViewModi fi er • ୈ1Ҿ͕ج४ͱͳΔAlignment e.g. VStack(alignment: .leading) ͷதʹೖ͍ͬͯΔViewΛௐ ͍ͨ͠ͳΒ .leading Λࢦఆ
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } .alignmentGuide(.trailing) { context in context.width * 2 } Color.white.frame(width: 1) }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } .alignmentGuide(.trailing) { context in context.width * 2 } Color.white.frame(width: 1) }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } .alignmentGuide(.trailing) { context in context.width * 2 } Circle() .fill(Color.green) .frame(width: 50, height: 50) Color.white.frame(width: 1) }
func alignmentGuide( _ g: HorizontalAlignment, computeValue: @escaping (ViewDimensions) -> CGFloat
) -> some View alignmentGuide(_:computeValue:) • ୈ2Ҿͷclosure • ௐ͢Δʢج४Ґஔ͔ΒͲΕ͘Β͍ͣΒ͔͢ʣΛฦ͢
func alignmentGuide( _ g: HorizontalAlignment, computeValue: @escaping (ViewDimensions) -> CGFloat
) -> some View alignmentGuide(_:computeValue:) • ୈ2Ҿͷclosure • ௐ͢Δʢج४Ґஔ͔ΒͲΕ͘Β͍ͣΒ͔͢ʣΛฦ͢ • ҾͷViewDimensions͔Βར༻Ͱ͖Δͷ
func alignmentGuide( _ g: HorizontalAlignment, computeValue: @escaping (ViewDimensions) -> CGFloat
) -> some View alignmentGuide(_:computeValue:) • ୈ2Ҿͷclosure • ௐ͢Δʢج४Ґஔ͔ΒͲΕ͘Β͍ͣΒ͔͢ʣΛฦ͢ • ҾͷViewDimensions͔Βར༻Ͱ͖Δͷ • Viewͷwidth, height • ֤Alignment GuideҐஔʢoffsetʣ
func alignmentGuide( _ g: HorizontalAlignment, computeValue: @escaping (ViewDimensions) -> CGFloat
) -> some View alignmentGuide(_:computeValue:) • ୈ2Ҿͷclosure • ௐ͢Δʢج४Ґஔ͔ΒͲΕ͘Β͍ͣΒ͔͢ʣΛฦ͢ • ҾͷViewDimensions͔Βར༻Ͱ͖Δͷ • Viewͷwidth, height • ֤Alignment GuideҐஔʢoffsetʣ
func alignmentGuide( _ g: HorizontalAlignment, computeValue: @escaping (ViewDimensions) -> CGFloat
) -> some View alignmentGuide(_:computeValue:) • ୈ2Ҿͷclosure • ௐ͢Δʢج४Ґஔ͔ΒͲΕ͘Β͍ͣΒ͔͢ʣΛฦ͢ • ҾͷViewDimensions͔Βར༻Ͱ͖Δͷ • Viewͷwidth, height • ֤Alignment GuideҐஔʢoffsetʣ
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } Color.white.frame(width: 1) }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } Color.white.frame(width: 1) }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } .alignmentGuide(.trailing) { context in context.width * 2 } Color.white.frame(width: 1) }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } .alignmentGuide(.trailing) { context in context.width * 2 } Color.white.frame(width: 1) }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } .alignmentGuide(.trailing) { context in context.width * 2 } Color.white.frame(width: 1) } 🤔* 2ʁ
🤔* 2ʁ
func alignmentGuide( _ g: HorizontalAlignment, computeValue: @escaping (ViewDimensions) -> CGFloat
) -> some View alignmentGuide(_:computeValue:) • ୈ2Ҿͷclosure • ௐ͢Δʢج४Ґஔ͔ΒͲΕ͘Β͍ͣΒ͔͢ʣΛฦ͢
func alignmentGuide( _ g: HorizontalAlignment, computeValue: @escaping (ViewDimensions) -> CGFloat
) -> some View alignmentGuide(_:computeValue:) • ୈ2Ҿͷclosure • ௐ͢Δʢج४Ґஔ͔ΒͲΕ͘Β͍ͣΒ͔͢ʣΛฦ͢ طଘͷΘΓʹ
ϓϨʔϯͳঢ়ଶ == 0 VStack(alignment: .trailing) ˞Πϝʔδ
.trailingͷσϑΥϧτ ϓϨʔϯͳঢ়ଶ == 0 VStack(alignment: .trailing) ˞Πϝʔδ
.trailingͷσϑΥϧτ .alignmentGuide(.trailing) { context in context.width * 2 }
.trailingͷσϑΥϧτ .alignmentGuide(.trailing) { context in context.width * 2 } طଘΛஔ͖͑Δ
.trailingͷσϑΥϧτ .alignmentGuide(.trailing) { context in context.width * 2 } طଘΛஔ͖͑Δ
.trailingͷσϑΥϧτ ͷҐஔ͔Β Ҡಈ͢Δ༁Ͱͳ͍
ϓϨʔϯͳঢ়ଶ == 0 .alignmentGuide(.trailing) { context in context.width * 2
} ˞Πϝʔδ
context.width * 2 ϓϨʔϯͳঢ়ଶ == 0 .alignmentGuide(.trailing) { context in
context.width * 2 } ˞Πϝʔδ
🙅 .trailingͷσϑΥϧτ ͔Β context.width * 2 ͣΒ͢ .alignmentGuide(.trailing) { context
in context.width * 2 } 🙆 .trailingͷσϑΥϧτ ͔Β context.width * 2 ʹஔ͖͑Δ VStack(alignment: .trailing)
func alignmentGuide( _ g: HorizontalAlignment, computeValue: @escaping (ViewDimensions) -> CGFloat
) -> some View alignmentGuide(_:computeValue:) • ୈ2Ҿͷclosure • ௐͨ͠ʢج४Ґஔ͔ΒͲΕ͘Β͍ͣΒ͔͢ʣΛฦ͢ • ҾͷViewDimensions͔Βར༻Ͱ͖Δͷ • Viewͷwidth, height • ֤Alignment GuideҐஔʢoffsetʣ
subscript(guide: VerticalAlignment) -> CGFloat { get } subscript(guide: HorizontalAlignment) ->
CGFloat { get } ViewDimensions https://developer.apple.com/documentation/swiftui/viewdimensions subscript(explicit guide: VerticalAlignment) -> CGFloat? { get } subscript(explicit guide: HorizontalAlignment) -> CGFloat? { get }
subscript(guide: VerticalAlignment) -> CGFloat { get } subscript(guide: HorizontalAlignment) ->
CGFloat { get } ViewDimensions https://developer.apple.com/documentation/swiftui/viewdimensions subscript(explicit guide: VerticalAlignment) -> CGFloat? { get } subscript(explicit guide: HorizontalAlignment) -> CGFloat? { get }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } .alignmentGuide(.trailing) { context in if context.width < 120 { return context[.leading] } else if context.width < 180 { return context[.trailing] } else { return -50 } } Color.white.frame(width: 1) }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } .alignmentGuide(.trailing) { context in if context.width < 120 { return context[.leading] } else if context.width < 180 { return context[.trailing] } else { return -50 } } Color.white.frame(width: 1) }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } .alignmentGuide(.trailing) { context in if context.width < 120 { return context[.leading] } else if context.width < 180 { return context[.trailing] } else { return -50 } } Color.white.frame(width: 1) }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } .alignmentGuide(.trailing) { context in if context.width < 120 { return context[.leading] } else if context.width < 180 { return context[.trailing] } else { return -50 } } Color.white.frame(width: 1) } == 0 == context.width
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) // লུ .alignmentGuide(.trailing)
{ context in if context.width < 120 { return context[.leading] } else if context.width < 180 { return context[.trailing] } else { return -50 } } Color.white.frame(width: 1) }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) // লུ .alignmentGuide(.leading)
{ _ in 100 } .alignmentGuide(.trailing) { context in if context.width < 120 { return context[.leading] } else if context.width < 180 { return context[.trailing] } else { return -50 } } Color.white.frame(width: 1) } ˞ VStackͰ.leading͕ࢦఆ͞Ε͍ͯͳ͍ͷͰɺ ͜Ε୯ମͰϨΠΞτʹӨڹͳ͍
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) // লུ .alignmentGuide(.leading)
{ _ in 100 } .alignmentGuide(.trailing) { context in if context.width < 120 { return context[.leading] } else if context.width < 180 { return context[.trailing] } else { return -50 } } Color.white.frame(width: 1) }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) // লུ .alignmentGuide(.leading)
{ _ in 100 } .alignmentGuide(.trailing) { context in if context.width < 120 { return context[.leading] } else if context.width < 180 { return context[.trailing] } else { return -50 } } Color.white.frame(width: 1) } != 0
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) // লུ .alignmentGuide(.leading)
{ _ in 100 } .alignmentGuide(.trailing) { context in if context.width < 120 { return context[.leading] } else if context.width < 180 { return context[.trailing] } else { return -50 } } Color.white.frame(width: 1) } == 100
subscript(guide: VerticalAlignment) -> CGFloat { get } subscript(guide: HorizontalAlignment) ->
CGFloat { get } ViewDimensions https://developer.apple.com/documentation/swiftui/viewdimensions subscript(explicit guide: VerticalAlignment) -> CGFloat? { get } subscript(explicit guide: HorizontalAlignment) -> CGFloat? { get }
subscript(guide: VerticalAlignment) -> CGFloat { get } subscript(guide: HorizontalAlignment) ->
CGFloat { get } ViewDimensions https://developer.apple.com/documentation/swiftui/viewdimensions subscript(explicit guide: VerticalAlignment) -> CGFloat? { get } subscript(explicit guide: HorizontalAlignment) -> CGFloat? { get }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) // লུ .alignmentGuide(.leading)
{ _ in 100 } .alignmentGuide(.trailing) { context in if context.width < 120 { return context[.leading] } else if context.width < 180 { return context[.trailing] } else { return -50 } } Color.white.frame(width: 1) }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) // লུ .alignmentGuide(.leading)
{ _ in 100 } .alignmentGuide(.trailing) { context in if context.width < 120 { return context[explicit: .leading] ?? -50 } else if context.width < 180 { return context[.trailing] } else { return -50 } } Color.white.frame(width: 1) }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) // লུ .alignmentGuide(.leading)
{ _ in 100 } .alignmentGuide(.trailing) { context in if context.width < 120 { return context[explicit: .leading] ?? -50 } else if context.width < 180 { return context[.trailing] } else { return -50 } } Color.white.frame(width: 1) } มԽͳ͠
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) // লུ .alignmentGuide(.leading)
{ _ in 100 } .alignmentGuide(.trailing) { context in if context.width < 120 { return context[explicit: .leading] ?? -50 } else if context.width < 180 { return context[.trailing] } else { return -50 } } Color.white.frame(width: 1) } มԽͳ͠ != nil == 100
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) // লུ //
.alignmentGuide(.leading) { _ in // 100 // } .alignmentGuide(.trailing) { context in if context.width < 120 { return context[explicit: .leading] ?? -50 } else if context.width < 180 { return context[.trailing] } else { return -50 } } Color.white.frame(width: 1) }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) // লུ //
.alignmentGuide(.leading) { _ in // 100 // } .alignmentGuide(.trailing) { context in if context.width < 120 { return context[explicit: .leading] ?? -50 } else if context.width < 180 { return context[.trailing] } else { return -50 } } Color.white.frame(width: 1) }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) // লུ //
.alignmentGuide(.leading) { _ in // 100 // } .alignmentGuide(.trailing) { context in if context.width < 120 { return context[explicit: .leading] ?? -50 } else if context.width < 180 { return context[.trailing] } else { return -50 } } Color.white.frame(width: 1) }
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) // লུ //
.alignmentGuide(.leading) { _ in // 100 // } .alignmentGuide(.trailing) { context in if context.width < 120 { return context[explicit: .leading] ?? -50 } else if context.width < 180 { return context[.trailing] } else { return -50 } } Color.white.frame(width: 1) } == nil
subscript(guide: VerticalAlignment) -> CGFloat { get } subscript(guide: HorizontalAlignment) ->
CGFloat { get } ViewDimensions https://developer.apple.com/documentation/swiftui/viewdimensions subscript(explicit guide: VerticalAlignment) -> CGFloat? { get } subscript(explicit guide: HorizontalAlignment) -> CGFloat? { get } σϑΥϧτɾஔ͖͑ΒΕͨΛऔಘ ஔ͖͑ΒΕͨΛऔಘʢஔ͖͑ΒΕ͍ͯͳ͍߹ nilʣ
💡tips
cf. https://developer.apple.com/documentation/swiftui/view/alignmentguide(_:computevalue:)-9mdoh Changing the alignment of one view may have
effects on surrounding views.
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } .alignmentGuide(.trailing) { context in // লུ } Color.white.frame(width: 1) } .frame(maxHeight: 500) .border(.white)
VStack(alignment: .trailing, spacing: 20) { Color.red.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } .alignmentGuide(.trailing) { context in // লུ } Color.red.frame(width: 1) } .frame(maxHeight: 500) .border(.white)
VStack(alignment: .trailing, spacing: 20) { Color.red.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } .alignmentGuide(.trailing) { context in // লུ } Color.red.frame(width: 1) } .frame(maxHeight: 500) .border(.white)
֎ଆͷStackͷframe͕มԽ͠͏Δ
☕ offset(x:y:)
func offset( x: CGFloat = 0, y: CGFloat = 0
) -> some View offset(x:y:) https://developer.apple.com/documentation/swiftui/view/offset(x:y:) • ViewΛਫฏ/ਨํʹҠಈ͢ΔViewModi fi er
VStack { Text("🐶") Text("🐱") Text("🐰") }
VStack { Text("🐶") Text("🐱") .offset(x: 50, y: 100) Text("🐰") }
cf. https://developer.apple.com/documentation/swiftui/view/offset(x:y:) Use offset(x:y:) to shift the displayed contents by
the amount speci fi ed in the x and y parameters. The original dimensions of the view aren’t changed by offsetting the contents.
VStack(spacing: 20) { Text("🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰") Text("Offset by passing horizontal & vertical
distance") .border(Color.green) .padding() } .border(.red) offset(x:y:)
VStack(spacing: 20) { Text("🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰") Text("Offset by passing horizontal & vertical
distance") .border(Color.green) .offset(x: 20, y: 50) .border(Color.gray) .padding() } .border(.red) offset(x:y:)
VStack(spacing: 20) { Text("🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰") Text("Offset by passing horizontal & vertical
distance") .border(Color.green) .offset(x: 20, y: 50) .border(Color.gray) .padding() } .border(.red) offset(x:y:)
VStack(spacing: 20) { Text("🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰") Text("Offset by passing horizontal & vertical
distance") .border(Color.green) .offset(x: 20, y: 50) .border(Color.gray) .padding() } .border(.red) offset(x:y:)
VStack(spacing: 20) { Text("🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰") Text("Offset by passing horizontal & vertical
distance") .border(Color.green) .offset(x: 20, y: 50) .border(Color.gray) .padding() } .border(.red) offset(x:y:)
alignmentGuide(_:computeValue:) vs. offset(x:y:)
alignmentGuide(_:computeValue:)
alignmentGuide(_:computeValue:) offset(x:y:)
Text("Offset by passing horizontal & vertical distance") .border(Color.green) .offset(x: 20,
y: 50) .border(Color.gray)
Text("Offset by passing horizontal & vertical distance") .border(Color.green) .offset(x: 20,
y: 50) .border(Color.gray)
Text("Offset by passing horizontal & vertical distance") .border(Color.green) .offset(x: 20,
y: 50) .border(Color.gray)
Text("Offset by passing horizontal & vertical distance") .border(Color.green) .offset(x: 20,
y: 50) .border(Color.orange) .offset(x: 20, y: 50) .border(Color.pink) .offset(x: 20, y: 50) .border(Color.gray)
Text("Offset by passing horizontal & vertical distance") .border(Color.green) .offset(x: 20,
y: 50) .border(Color.orange) .offset(x: 20, y: 50) .border(Color.pink) .offset(x: 20, y: 50) .border(Color.gray)
Text("Offset by passing horizontal & vertical distance") .border(Color.green) .offset(x: 20,
y: 50) .border(Color.orange) .offset(x: 20, y: 50) .border(Color.pink) .offset(x: 20, y: 50) .border(Color.gray)
Text("Offset by passing horizontal & vertical distance") .border(Color.green) .offset(x: 20,
y: 50) .border(Color.orange) .offset(x: 20, y: 50) .border(Color.pink) .offset(x: -20, y: 50) .border(Color.gray)
Text("Offset by passing horizontal & vertical distance") .border(Color.green) .offset(x: 20,
y: 50) .border(Color.orange) .offset(x: 20, y: 50) .border(Color.pink) .offset(x: -20, y: 50) .border(Color.gray)
ୈষ Custom Alignment Guide
ྫ
HStack(alignment: .bottom) { Color.white.frame(height: 1) VStack { Rectangle() .fill(.blue) .frame(width:
100, height: 400) Text("Long Long Long Blue Bar") .font(.title) } VStack { Text(“🐰🐢") .font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar”) .font(.title) Text("iOSDC 2022 sample code #1") .font(.caption) } Text(“Side\nText") .font(.title) Color.white.frame(height: 1) }
None
ղྫ
extension VerticalAlignment { private struct BlueBarTitleAlignment: AlignmentID { static func
defaultValue(in context: ViewDimensions) -> CGFloat { context[.bottom] } } static let blueBarTitleAlignment = VerticalAlignment( BlueBarTitleAlignment.self ) }
HStack(alignment: .bottom) { Color.white.frame(height: 1) VStack { Rectangle().fill(.blue) .frame(width: 100,
height: 400) Text("Long Long Long Blue Bar") .font(.title) } VStack { Text(“🐰🐢").font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar”).font(.title) Text("iOSDC 2022 sample code #1") .font(.caption) } Text(“Side\nText").font(.title) Color.white.frame(height: 1) }
HStack(alignment: .blueBarTitleAlignment) { Color.white.frame(height: 1) VStack { Rectangle().fill(.blue) .frame(width: 100,
height: 400) Text("Long Long Long Blue Bar") .font(.title) } VStack { Text("🐰🐢").font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar”).font(.title) Text("iOSDC 2022 sample code #1") .font(.caption) } Text("Side\nText").font(.title) Color.white.frame(height: 1) }
HStack(alignment: .blueBarTitleAlignment) { Color.white.frame(height: 1) VStack { Rectangle().fill(.blue) .frame(width: 100,
height: 400) Text("Long Long Long Blue Bar") .font(.title) .alignmentGuide(.blueBarTitleAlignment) { context in context[.firstTextBaseline] } } VStack { Text("🐰🐢").font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar").font(.title) .alignmentGuide(.blueBarTitleAlignment) { context in context[.firstTextBaseline] } Text("iOSDC 2022 sample code #1") .font(.caption) } Text("Side\nText").font(.title) Color.white.frame(height: 1) }
ղઆ
Take 1
Built-in Alignment Guides
HStack(alignment: .bottom) { Color.white.frame(height: 1) VStack { Rectangle() .fill(.blue) .frame(width:
100, height: 400) Text("Long Long Long Blue Bar") .font(.title) } VStack { Text(“🐰🐢") .font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar”) .font(.title) Text("iOSDC 2022 sample code #1") .font(.caption) } Text(“Side\nText") .font(.title) Color.white.frame(height: 1) }
HStack(alignment: .firstTextBaseline) { Color.white.frame(height: 1) VStack { Rectangle() .fill(.blue) .frame(width:
100, height: 400) Text("Long Long Long Blue Bar") .font(.title) } VStack { Text(“🐰🐢") .font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar”) .font(.title) Text("iOSDC 2022 sample code #1") .font(.caption) } Text(“Side\nText") .font(.title) Color.white.frame(height: 1) }
HStack(alignment: .firstTextBaseline) { Color.white.frame(height: 1) VStack { Rectangle() .fill(.blue) .frame(width:
100, height: 400) Text("Long Long Long Blue Bar") .font(.title) } VStack { Text(“🐰🐢") .font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar”) .font(.title) Text("iOSDC 2022 sample code #1") .font(.caption) } Text(“Side\nText") .font(.title) Color.white.frame(height: 1) }
HStack(alignment: .firstTextBaseline) { Color.white.frame(height: 1) VStack { Rectangle() .fill(.blue) .frame(width:
100, height: 400) Text("Long Long Long Blue Bar") .font(.title) } VStack { Text(“🐰🐢") .font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar”) .font(.title) Text("iOSDC 2022 sample code #1") .font(.caption) } Text(“Side\nText") .font(.title) Color.white.frame(height: 1) } ࣮ݱ͍ͨ͠ϨΠΞτ
Take 2
alignmentGuide(_:computeValue:)
HStack(alignment: .bottom) { Color.white.frame(height: 1) VStack { Rectangle().fill(.blue) .frame(width: 100,
height: 400) Text("Long Long Long Blue Bar”).font(.title) } VStack { Text(“🐰🐢").font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar”).font(.title) Text("iOSDC 2022 sample code #1").font(.caption) } Text(“Side\nText").font(.title) Color.white.frame(height: 1) }
HStack(alignment: .bottom) { Color.white.frame(height: 1) VStack { Rectangle().fill(.blue) .frame(width: 100,
height: 400) Text("Long Long Long Blue Bar").font(.title) .alignmentGuide(.bottom) { context in context[.firstTextBaseline] } } VStack { Text(“🐰🐢").font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar”).font(.title) .alignmentGuide(.bottom) { context in context[.firstTextBaseline] } Text("iOSDC 2022 sample code #1").font(.caption) } Text(“Side\nText").font(.title) Color.white.frame(height: 1) }
HStack(alignment: .bottom) { Color.white.frame(height: 1) VStack { Rectangle().fill(.blue) .frame(width: 100,
height: 400) Text("Long Long Long Blue Bar").font(.title) .alignmentGuide(.bottom) { context in context[.firstTextBaseline] } } VStack { Text(“🐰🐢").font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar”).font(.title) .alignmentGuide(.bottom) { context in context[.firstTextBaseline] } Text("iOSDC 2022 sample code #1").font(.caption) } Text(“Side\nText").font(.title) Color.white.frame(height: 1) } มԽͳ͠
HStack(alignment: .bottom) { Color.white.frame(height: 1) VStack(alignment: .center) { Rectangle().fill(.blue) .frame(width:
100, height: 400) Text("Long Long Long Blue Bar").font(.title) .alignmentGuide(.bottom) { context in context[.firstTextBaseline] } } VStack(alignment: .center) { Text(“🐰🐢").font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar”).font(.title) .alignmentGuide(.bottom) { context in context[.firstTextBaseline] } Text("iOSDC 2022 sample code #1").font(.caption) } Text(“Side\nText").font(.title) Color.white.frame(height: 1) } มԽͳ͠
HStack(alignment: .bottom) { Color.white.frame(height: 1) VStack(alignment: .center) { Rectangle().fill(.blue) .frame(width:
100, height: 400) Text("Long Long Long Blue Bar").font(.title) .alignmentGuide(.bottom) { context in context[.firstTextBaseline] } } VStack(alignment: .center) { Text(“🐰🐢").font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar”).font(.title) .alignmentGuide(.bottom) { context in context[.firstTextBaseline] } Text("iOSDC 2022 sample code #1").font(.caption) } Text(“Side\nText").font(.title) Color.white.frame(height: 1) } มԽͳ͠
Built-in Alignment Guides + alignmentGuide(_:computeValue:) StackΛ·͍ͨͰViewΛἧ͑Δ͜ͱͰ͖ͳ͍
HStack(alignment: .bottom) { Color.white.frame(height: 1) VStack { Rectangle().fill(.blue) .frame(width: 100,
height: 400) Text("Long Long Long Blue Bar”).font(.title) } VStack { Text(“🐰🐢").font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar”).font(.title) Text("iOSDC 2022 sample code #1").font(.caption) } Text(“Side\nText").font(.title) Color.white.frame(height: 1) }
HStack(alignment: .bottom) { Color.white.frame(height: 1) VStack { Rectangle().fill(.blue) .frame(width: 100,
height: 400) Text("Long Long Long Blue Bar").font(.title) } .alignmentGuide(.bottom) { context in context[.firstTextBaseline] } VStack { Text(“🐰🐢").font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar”).font(.title) Text("iOSDC 2022 sample code #1").font(.caption) } .alignmentGuide(.bottom) { context in context[.firstTextBaseline] } Text(“Side\nText").font(.title) Color.white.frame(height: 1) }
HStack(alignment: .bottom) { Color.white.frame(height: 1) VStack { Rectangle().fill(.blue) .frame(width: 100,
height: 400) Text("Long Long Long Blue Bar").font(.title) } .alignmentGuide(.bottom) { context in context[.firstTextBaseline] } VStack { Text(“🐰🐢").font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar”).font(.title) Text("iOSDC 2022 sample code #1").font(.caption) } .alignmentGuide(.bottom) { context in ???????????????? } Text(“Side\nText").font(.title) Color.white.frame(height: 1) } ̎ͭͷςΩετʹἧ͑Δͪΐ͏Ͳྑ͍ΛฦͤΔ…ʁ
Take 3
Custom Alignment Guide
protocol AlignmentID
public protocol AlignmentID { static func defaultValue(in context: ViewDimensions) ->
CGFloat }
public protocol AlignmentID { static func defaultValue(in context: ViewDimensions) ->
CGFloat } HStackͳͲͰࢦఆͨ͠ࡍͷσϑΥϧτ
private struct BlueBarTitleAlignment: AlignmentID { static func defaultValue(in context: ViewDimensions)
-> CGFloat { context[.bottom] } }
extension VerticalAlignment { private struct BlueBarTitleAlignment: AlignmentID { static func
defaultValue(in context: ViewDimensions) -> CGFloat { context[.bottom] } } static let blueBarTitleAlignment = VerticalAlignment( BlueBarTitleAlignment.self ) }
HStack(alignment: .bottom) { Color.white.frame(height: 1) VStack { Rectangle().fill(.blue) .frame(width: 100,
height: 400) Text("Long Long Long Blue Bar") .font(.title) } VStack { Text("🐰🐢").font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar”).font(.title) Text("iOSDC 2022 sample code #1”) .font(.caption) } Text("Side\nText").font(.title) Color.white.frame(height: 1) }
HStack(alignment: .blueBarTitleAlignment) { Color.white.frame(height: 1) VStack { Rectangle().fill(.blue) .frame(width: 100,
height: 400) Text("Long Long Long Blue Bar") .font(.title) } VStack { Text("🐰🐢").font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar”).font(.title) Text("iOSDC 2022 sample code #1") .font(.caption) } Text("Side\nText").font(.title) Color.white.frame(height: 1) }
HStack(alignment: .blueBarTitleAlignment) { Color.white.frame(height: 1) VStack { Rectangle().fill(.blue) .frame(width: 100,
height: 400) Text("Long Long Long Blue Bar") .font(.title) .alignmentGuide(.blueBarTitleAlignment) { context in context[.firstTextBaseline] } } VStack { Text("🐰🐢").font(.title) Rectangle().fill(.blue) .frame(width: 150, height: 200) Text("Short Blue Bar").font(.title) .alignmentGuide(.blueBarTitleAlignment) { context in context[.firstTextBaseline] } Text("iOSDC 2022 sample code #1") .font(.caption) } Text("Side\nText").font(.title) Color.white.frame(height: 1) }
• StackΛލ͍ͰViewΛἧ͍͑ͨ Custom Alignment Guide ͷ͍ॴ
• StackΛލ͍ͰViewΛἧ͍͑ͨ • alignmentGuide(_:computeValue:) Λ͍ճ͍ͨ͠ • ViewDimentionsͷ͚ͩͰܭࢉͰ͖Δ߹ Custom Alignment Guide
ͷ͍ॴ
VStack(alignment: .trailing, spacing: 20) { Color.white.frame(width: 1) ForEach(["Dog", "Crocodile", "Horse",
"Rhinoceros"], id: \.self) { Text($0) .font(.largeTitle) .padding() .background(Color.green) } .alignmentGuide(.trailing) { context in context.width * 2 } Color.white.frame(width: 1) }
Stack × Custom Alignment Guide ͷ ੍
None
̎ϲॴἧ͑
۠Γઢ
None
VStack(alignment: .profileListRowTextAlignment, spacing: 8) { // লུ HStack(spacing: 24) {
Text("ϫΠϯΤΩεύʔτೝఆ൪߸") .font(.caption) Text("1234567890") .font(.caption) } // লུ }
VStack(alignment: .profileListRowTextAlignment, spacing: 8) { // লུ HStack(spacing: 24) {
Text("ϫΠϯΤΩεύʔτೝఆ൪߸") .font(.caption) Text("1234567890") .font(.caption) .alignmentGuide(.profileListRowTextAlignment) { $0[.leading] - 30 } } // লུʢଞͷTextʹalignmentGuideΛ༩ʣ }
VStack(alignment: .profileListRowTextAlignment, spacing: 8) { // লུ HStack(spacing: 24) {
Text("ϫΠϯΤΩεύʔτೝఆ൪߸") .font(.caption) Text("1234567890") .font(.caption) .alignmentGuide(.profileListRowTextAlignment) { $0[.leading] - 30 } } // লུʢଞͷTextʹalignmentGuideΛ༩ʣ }
VStack(alignment: .profileListRowTextAlignment, spacing: 8) { // লུ HStack(spacing: 24) {
Text("ϫΠϯΤΩεύʔτೝఆ൪߸") .font(.caption) .alignmentGuide(.profileListRowTextAlignment) { $0[.leading] } Text("1234567890") .font(.caption) .alignmentGuide(.profileListRowTextAlignment) { $0[.leading] - 30 } } // লུʢଞͷTextʹalignmentGuideΛ༩ʣ }
VStack(alignment: .profileListRowTextAlignment, spacing: 8) { // লུ HStack(spacing: 24) {
Text("ϫΠϯΤΩεύʔτೝఆ൪߸") .font(.caption) .alignmentGuide(.profileListRowTextAlignment) { $0[.leading] } Text("1234567890") .font(.caption) .alignmentGuide(.profileListRowTextAlignment) { $0[.leading] - 30 } } // লུʢଞͷTextʹalignmentGuideΛ༩ʣ } ͦΕͧΕ͕HStack͝ͱҠಈͤ͞ΔͷͰἧΘͳ͍…
• ಉ͡StackͷෳͷViewΛἧ͑ΒΕͳ͍ • ج४ͱͳΔ1ͭͷAlignmentʹରͯ͠ରͷViewΛؚΉStack શମͷҐஔΛௐ͢ΔΈͷͨΊ Stack × Custom Alignment Guide
ͷ੍
☕ Grid
VStack { SpeakerHeader() Grid(alignment: .leading, verticalSpacing: 8) { Divider() GridRow
{ Text("ϫΠϯΤΩεύʔτೝఆ൪߸") .lineLimit(1) .font(.caption) Text("1234567890") .font(.caption) } Divider() GridRow { Text("໊લ") .font(.caption) Text("monoqlo") .font(.caption) } GridRow { Text("ి൪߸") .font(.caption) Text("XXX-XXXX-XXXXX") .font(.caption) } } } .padding() .overlay( RoundedRectangle(cornerRadius: 8) .stroke(.gray) ) https://developer.apple.com/documentation/swiftui/grid
☕ • frame(width:height:alignment:) • frame(minWidth:idealWidth:maxWidth:minHeight:ide alHeight:maxHeight:alignment:)
HStack { Image("monoqloIcon") .resizable() .frame(width: 50, height: 50) .clipShape(Circle()) HStack
{ VStack(alignment: .leading) { Text("monoqlo") .font(.headline) Text("iOSDC 2022") .font(.body) } } .border(.gray) Image(systemName: "heart") .foregroundColor(.pink) .padding() .border(.gray) } .frame(width: 300) .padding() .border(.green)
HStack { Image("monoqloIcon") .resizable() .frame(width: 50, height: 50) .clipShape(Circle()) HStack
{ VStack(alignment: .leading) { Text("monoqlo") .font(.headline) Text("iOSDC 2022") .font(.body) } .frame(maxWidth: .infinity, alignment: .leading) } .border(.gray) Image(systemName: "heart") .foregroundColor(.pink) .padding() .border(.gray) } .frame(width: 300) .padding() .border(.green)
Text(""" ⭐ monoqlo ⭐ ⭐ iOSDC 2022 ⭐ """) .border(.red)
Text(""" ⭐ monoqlo ⭐ ⭐ iOSDC 2022 ⭐ """) .border(.red)
.frame(alignment: .bottom)) .border(.white)
Text(""" ⭐ monoqlo ⭐ ⭐ iOSDC 2022 ⭐ """) .border(.red)
.alignmentGuide(.bottom) { $0[.firstTextBaseline] } .frame(alignment: .bottom)) .border(.white)
VStack { Text("top") Text(""" ⭐ monoqlo ⭐ ⭐ iOSDC 2022
⭐ """) .border(.red) Text("bottom") }
VStack { Text("top") Text(""" ⭐ monoqlo ⭐ ⭐ iOSDC 2022
⭐ """) .border(.red) Text("bottom") } .frame(height: 200, alignment: .init(horizontal: .center, vertical: .frameTextAlignment)) .border(.white)
VStack { Text("top") Text(""" ⭐ monoqlo ⭐ ⭐ iOSDC 2022
⭐ """) .border(.red) Text("bottom") } .frame(height: 200, alignment: .init(horizontal: .center, vertical: .frameTextAlignment)) .border(.white) private extension VerticalAlignment { struct FrameTextAlignment: AlignmentID { static func defaultValue(in context: ViewDimensions) -> CGFloat { context[.bottom] } } static let frameTextAlignment = VerticalAlignment( FrameTextAlignment.self ) }
VStack { Text("top") Text(""" ⭐ monoqlo ⭐ ⭐ iOSDC 2022
⭐ """) .border(.red) Text("bottom") } .frame(height: 200, alignment: .init(horizontal: .center, vertical: .frameTextAlignment)) .border(.white)
VStack { Text("top") Text(""" ⭐ monoqlo ⭐ ⭐ iOSDC 2022
⭐ """) .border(.red) .alignmentGuide(.frameTextAlignment) { $0[.firstTextBaseline] } Text("bottom") } .frame(height: 200, alignment: .init(horizontal: .center, vertical: .frameTextAlignment)) .border(.white)
🤔 alignmentGuide(_:computeValue:) vs. offset(x:y:)
alignmentGuide(_:computeValue:) offset(x:y:)
alignmentGuide(_:computeValue:) offset(x:y:) ※ Stackͷalignmentʹରͯͬͨ࣌͠
• frame(alignment:) • frame(minWidth:idealWidth:maxWidth:minHeight:idealHeight: maxHeight:alignment:) + alignmentGuide(_:computeValue:)
Alignment Guide ೖͰ͖ͨͰ͠ΐ͏͔ʁ
ࣗݾհ
@monoqloʢͷ͘Ζʣ • 2લ͔ΒϦΫϧʔτͷਓ • ελσΟαϓϦENGLISH୲
None
None
None
Appendix
• Alignment • https://developer.apple.com/documentation/swiftui/alignment • https://developer.apple.com/documentation/swiftui/verticalalignment • https://developer.apple.com/documentation/swiftui/horizontalalignment • https://developer.apple.com/documentation/swiftui/aligning-views-within-a-stack
• alignmentguide(_:computevalue:) • https://developer.apple.com/documentation/swiftui/view/alignmentguide(_:computevalue:)-9mdoh • https://developer.apple.com/documentation/swiftui/view/alignmentguide(_:computevalue:)-6y3u2 • https://developer.apple.com/documentation/swiftui/viewdimensions Appendix
• Custom Alignment Guide • https://developer.apple.com/documentation/swiftui/aligning-views-across-stacks • https://developer.apple.com/documentation/swiftui/alignmentid • https://developer.apple.com/documentation/swiftui/verticalalignment/init(_:)
• https://developer.apple.com/documentation/swiftui/horizontalalignment/init(_:) • offset(x:y:) • https://developer.apple.com/documentation/swiftui/view/offset(x:y:) Appendix
• Grid • https://developer.apple.com/documentation/swiftui/grid • Debug • https://developer.apple.com/documentation/swiftui/inspecting-view-layout Appendix