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.4k
入門 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
700
あなたのアプリ、✨リブランディング✨できますか? / 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
会社員しながら本を書いてきた知見の共有
sat
PRO
3
680
ProductZine Day 2025 Assuredのプロダクトディスカバリー
kechol
0
110
大規模PaaSにおける監視基盤の構築と効率化の道のり
lycorptech_jp
PRO
0
170
All About Sansan – for New Global Engineers
sansan33
PRO
1
1.2k
AIエージェントデザインパターンの選び方
almondo_event
0
130
ソフトウェアテストのAI活用_ver1.10
fumisuke
0
220
S3 Tables を図解でやさしくおさらい~基本から QuickSight 連携まで/s3-tables-illustrated-basics-quicksight
emiki
1
330
Houtou.pm #1
papix
0
650
Redmineの意外と知らない便利機能 (Redmine 6.0対応版)
vividtone
0
1.1k
Data Hubグループ 紹介資料
sansan33
PRO
0
1.7k
ゴリラ.vim #36 ~ Vim x SNS ~ スポンサーセッション
yasunori0418
1
310
それでもぼくらは貢献をつづけるのだ(たぶん) @FOSS4GLT会#002
furukawayasuto
1
270
Featured
See All Featured
StorybookのUI Testing Handbookを読んだ
zakiyama
30
5.8k
Art, The Web, and Tiny UX
lynnandtonic
298
21k
How STYLIGHT went responsive
nonsquared
100
5.6k
Java REST API Framework Comparison - PWX 2021
mraible
31
8.6k
Testing 201, or: Great Expectations
jmmastey
42
7.5k
Git: the NoSQL Database
bkeepers
PRO
430
65k
The Power of CSS Pseudo Elements
geoffreycrofte
76
5.8k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
10
840
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
123
52k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
Building Better People: How to give real-time feedback that sticks.
wjessup
368
19k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
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