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.5k
入門 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
710
あなたのアプリ、✨リブランディング✨できますか? / iosdc2020
monoqlo
9
1.5k
実践 CallKit/PushKit ときどき🐛退治 / iOSDC 2019
monoqlo
4
3.7k
「QRコード読み取り?楽勝ですよ😙」=>「AVFoundationを信じたおれがバカだった😇」 / iOSDC 2018
monoqlo
10
27k
WWDC2016のススメ
monoqlo
0
110
Other Decks in Technology
See All in Technology
Amazon ECS & AWS Fargate 運用アーキテクチャ2025 / Amazon ECS and AWS Fargate Ops Architecture 2025
iselegant
16
4.6k
データプラットフォーム技術におけるメダリオンアーキテクチャという考え方/DataPlatformWithMedallionArchitecture
smdmts
5
570
AIの最新技術&テーマをつまんで紹介&フリートークするシリーズ #1 量子機械学習の入門
tkhresk
0
130
JSX - 歴史を振り返り、⾯⽩がって、エモくなろう
pal4de
3
1.1k
Observability в PHP без боли. Олег Мифле, тимлид Altenar
lamodatech
0
290
Prox Industries株式会社 会社紹介資料
proxindustries
0
210
変化する開発、進化する体系時代に適応するソフトウェアエンジニアの知識と考え方(JaSST'25 Kansai)
mizunori
0
140
2年でここまで成長!AWSで育てたAI Slack botの軌跡
iwamot
PRO
2
360
Windows 11 で AWS Documentation MCP Server 接続実践/practical-aws-documentation-mcp-server-connection-on-windows-11
emiki
0
720
エンジニア向け技術スタック情報
kauche
0
110
20250625 Snowflake Summit 2025活用事例 レポート / Nowcast Snowflake Summit 2025 Case Study Report
kkuv
1
220
ユーザーのプロフィールデータを活用した推薦精度向上の取り組み
yudai00
0
490
Featured
See All Featured
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
20
1.3k
A Tale of Four Properties
chriscoyier
160
23k
A Modern Web Designer's Workflow
chriscoyier
693
190k
How to Think Like a Performance Engineer
csswizardry
24
1.7k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
50k
Producing Creativity
orderedlist
PRO
346
40k
Rails Girls Zürich Keynote
gr2m
94
14k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
48
2.8k
Facilitating Awesome Meetings
lara
54
6.4k
[RailsConf 2023] Rails as a piece of cake
palkan
55
5.6k
The Cult of Friendly URLs
andyhume
79
6.4k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
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