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
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
660
あなたのアプリ、✨リブランディング✨できますか? / iosdc2020
monoqlo
9
1.4k
実践 CallKit/PushKit ときどき🐛退治 / iOSDC 2019
monoqlo
4
3.4k
「QRコード読み取り?楽勝ですよ😙」=>「AVFoundationを信じたおれがバカだった😇」 / iOSDC 2018
monoqlo
10
26k
WWDC2016のススメ
monoqlo
0
98
Other Decks in Technology
See All in Technology
実践! ソフトウェアエンジニアリングの価値の計測 ── Effort、Output、Outcome、Impact
nomuson
0
2k
CDKのコードレビューを楽にするパッケージcdk-mentorを作ってみた/cdk-mentor
tomoki10
0
200
When Windows Meets Kubernetes…
pichuang
0
300
機械学習を「社会実装」するということ 2025年版 / Social Implementation of Machine Learning 2025 Version
moepy_stats
4
860
Cloudflareで実現する AIエージェント ワークフロー基盤
kmd09
0
280
Copilotの力を実感!3ヶ月間の生成AI研修の試行錯誤&成功事例をご紹介。果たして得たものとは・・?
ktc_shiori
0
340
Amazon Q Developerで.NET Frameworkプロジェクトをモダナイズしてみた
kenichirokimura
1
190
30分でわかるデータ分析者のためのディメンショナルモデリング #datatechjp / 20250120
kazaneya
PRO
22
4.8k
My small contributions - Fujiwara Tech Conference 2025
ijin
0
1.4k
JAWS-UG20250116_iOSアプリエンジニアがAWSreInventに行ってきた(真面目編)
totokit4
0
140
Git scrapingで始める継続的なデータ追跡 / Git Scraping
ohbarye
5
470
今から、 今だからこそ始める Terraform で Azure 管理 / Managing Azure with Terraform: The Perfect Time to Start
nnstt1
0
190
Featured
See All Featured
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.4k
Keith and Marios Guide to Fast Websites
keithpitt
410
22k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
38
1.9k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
Building an army of robots
kneath
302
45k
How to Think Like a Performance Engineer
csswizardry
22
1.3k
Site-Speed That Sticks
csswizardry
2
250
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
49
2.2k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
10
860
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
30
2.1k
Designing on Purpose - Digital PM Summit 2013
jponch
116
7.1k
Imperfection Machines: The Place of Print at Facebook
scottboms
267
13k
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