Upgrade to Pro — share decks privately, control downloads, hide ads and more …

入門 SwiftUI Alignment Guide / iOSDC2022

monoqlo
September 11, 2022

入門 SwiftUI Alignment Guide / iOSDC2022

iOSDC Japan 2022 2022/09/11

monoqlo

September 11, 2022
Tweet

More Decks by monoqlo

Other Decks in Technology

Transcript

  1. @monoqloʢ΋ͷ͘Ζʣ
    ೖ໳SwiftUI Alignment Guide
    iOSDC Japan 2022

    View full-size slide

  2. • ʮೖ໳ʯͱ͋ΔΑ͏ʹϝΠϯλʔήοτ͸SwiftUIॳ৺ऀͰ͢


    • ۩ମతʹ͸ŋŋŋ


    • alignmentGuide(_:computeValue:) ࢖ͬͨ͜ͱͳ͍


    • Custom Alignment Guide࢖ͬͨ͜ͱͳ͍


    • ࢖ͬͨ͜ͱ͋Δ͚ͲΑ͘Θ͔Βͳ͔ͬͨ
    ॳ৺ऀ޲͚ͷτʔΫͰ͢

    View full-size slide

  3. • 2,3೥લ͸͔ͬ͢Β͔ΜͩͬͨެࣜυΩϡϝϯτ…


    • ͍ͭͷ·ʹ͔େॆ࣮


    • ࠷ֶۙͼ࢝Ίͨਓ͸ٯʹΑ͘஌͍ͬͯΔՄೳੑ😇


    • ਖ਼௚͜ͷτʔΫͷඞཁੑΛٙ͏΄ͲΊͪΌͪ͘Όྑ͍ࢿྉ


    • ͔͍ͭ·ΜͰҾ༻ͭͭ͠ղઆ


    • εϥΠυͷ࠷ޙʹࢀߟจݙͱͯ͠URLهࡌ
    ࠷ۙͷެࣜυΩϡϝϯτ͸େॆ࣮

    View full-size slide

  4. ୈষ
    Alignment Guideͱ͸

    View full-size slide

  5. 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)


    }


    }

    View full-size slide

  6. 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)


    }


    }

    View full-size slide

  7. 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)


    }


    }

    View full-size slide

  8. VStack {


    Text("Hello,")


    Text("😺🐶🐢🐰🐳")


    Text("Animals!")


    }

    View full-size slide

  9. VStack {


    Text("Hello,")


    Text("😺🐶🐢🐰🐳")


    Text("Animals!")


    }

    View full-size slide

  10. VStack {


    Color.white.frame(width: 1)


    Text("Hello,")


    Text("😺🐶🐢🐰🐳")


    Text(“Animals!")


    Color.white.frame(width: 1)


    }

    View full-size slide

  11. VStack(alignment: .center) {


    Color.white.frame(width: 1)


    Text("Hello,")


    Text("😺🐶🐢🐰🐳")


    Text(“Animals!")


    Color.white.frame(width: 1)


    }

    View full-size slide

  12. VStack(alignment: .leading) {


    Color.white.frame(width: 1)


    Text("Hello,")


    Text("😺🐶🐢🐰🐳")


    Text(“Animals!")


    Color.white.frame(width: 1)


    }

    View full-size slide

  13. VStack(alignment: .leading) {


    Color.white.frame(width: 1)


    Text("Hello,")


    Text("😺🐶🐢🐰🐳")


    Text(“Animals!")


    Color.white.frame(width: 1)


    }


    .environment(\.layoutDirection, .rightToLeft)

    View full-size slide

  14. Built-in Alignment Guides

    View full-size slide

  15. HorizontalAlignment


    • leading


    • center


    • trailing


    • listRowSeparatorLeading


    • listRowSeparatorTrailing
    Built-in Alignment Guides
    VerticalAlignment


    • top


    • center


    • bottom



    fi
    rstTextBaseline


    • lastTextBaseline

    View full-size slide

  16. HorizontalAlignment


    • leading


    • center


    • trailing


    • (listRowSeparatorLeading)


    • (listRowSeparatorTrailing)
    Built-in Alignment Guides

    View full-size slide

  17. VerticalAlignment


    • top


    • center


    • bottom



    fi
    rstTextBaseline


    • lastTextBaseline
    Built-in Alignment Guides

    View full-size slide

  18. Alignment


    HorizontalAlignment


    ×


    VerticalAlignment
    Built-in Alignment Guides
    https://developer.apple.com/documentation/swiftui/alignment

    View full-size slide

  19. Built-in Alignment Guides

    View full-size slide

  20. Custom Alignment Guide

    View full-size slide

  21. ୈষ
    alignmentGuide(_:computeValue:)

    View full-size slide

  22. 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)


    }


    View full-size slide

  23. 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)


    }

    View full-size slide

  24. 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)


    }

    View full-size slide

  25. alignmentGuide(_:computeValue:)

    View full-size slide

  26. 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

    View full-size slide

  27. func alignmentGuide(
    _ g: HorizontalAlignment,
    computeValue: @escaping (ViewDimensions) -> CGFloat
    ) -> some View
    alignmentGuide(_:computeValue:)
    • ج४ͱͳΔAlignment͔ΒͷҐஔΛௐ੔Ͱ͖ΔViewModi
    fi
    er

    View full-size slide

  28. 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 Λࢦఆ

    View full-size slide

  29. 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)


    }

    View full-size slide

  30. 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)


    }

    View full-size slide

  31. 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)


    }

    View full-size slide

  32. func alignmentGuide(
    _ g: HorizontalAlignment,
    computeValue: @escaping (ViewDimensions) -> CGFloat
    ) -> some View
    alignmentGuide(_:computeValue:)
    • ୈ2Ҿ਺ͷclosure


    • ௐ੔͢Δ஋ʢج४Ґஔ͔ΒͲΕ͘Β͍ͣΒ͔͢ʣΛฦ͢

    View full-size slide

  33. func alignmentGuide(
    _ g: HorizontalAlignment,
    computeValue: @escaping (ViewDimensions) -> CGFloat
    ) -> some View
    alignmentGuide(_:computeValue:)
    • ୈ2Ҿ਺ͷclosure


    • ௐ੔͢Δ஋ʢج४Ґஔ͔ΒͲΕ͘Β͍ͣΒ͔͢ʣΛฦ͢


    • Ҿ਺ͷViewDimensions͔Βར༻Ͱ͖Δ΋ͷ

    View full-size slide

  34. func alignmentGuide(
    _ g: HorizontalAlignment,
    computeValue: @escaping (ViewDimensions) -> CGFloat
    ) -> some View
    alignmentGuide(_:computeValue:)
    • ୈ2Ҿ਺ͷclosure


    • ௐ੔͢Δ஋ʢج४Ґஔ͔ΒͲΕ͘Β͍ͣΒ͔͢ʣΛฦ͢


    • Ҿ਺ͷViewDimensions͔Βར༻Ͱ͖Δ΋ͷ


    • Viewͷwidth, height


    • ֤Alignment GuideҐஔʢoffset஋ʣ

    View full-size slide

  35. func alignmentGuide(
    _ g: HorizontalAlignment,
    computeValue: @escaping (ViewDimensions) -> CGFloat
    ) -> some View
    alignmentGuide(_:computeValue:)
    • ୈ2Ҿ਺ͷclosure


    • ௐ੔͢Δ஋ʢج४Ґஔ͔ΒͲΕ͘Β͍ͣΒ͔͢ʣΛฦ͢


    • Ҿ਺ͷViewDimensions͔Βར༻Ͱ͖Δ΋ͷ


    • Viewͷwidth, height


    • ֤Alignment GuideҐஔʢoffset஋ʣ

    View full-size slide

  36. func alignmentGuide(
    _ g: HorizontalAlignment,
    computeValue: @escaping (ViewDimensions) -> CGFloat
    ) -> some View
    alignmentGuide(_:computeValue:)
    • ୈ2Ҿ਺ͷclosure


    • ௐ੔͢Δ஋ʢج४Ґஔ͔ΒͲΕ͘Β͍ͣΒ͔͢ʣΛฦ͢


    • Ҿ਺ͷViewDimensions͔Βར༻Ͱ͖Δ΋ͷ


    • Viewͷwidth, height


    • ֤Alignment GuideҐஔʢoffset஋ʣ

    View full-size slide

  37. 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)


    }

    View full-size slide

  38. 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)


    }

    View full-size slide

  39. 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)


    }

    View full-size slide

  40. 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)


    }

    View full-size slide

  41. 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ʁ

    View full-size slide

  42. func alignmentGuide(
    _ g: HorizontalAlignment,
    computeValue: @escaping (ViewDimensions) -> CGFloat
    ) -> some View
    alignmentGuide(_:computeValue:)
    • ୈ2Ҿ਺ͷclosure


    • ௐ੔͢Δ஋ʢج४Ґஔ͔ΒͲΕ͘Β͍ͣΒ͔͢ʣΛฦ͢

    View full-size slide

  43. func alignmentGuide(
    _ g: HorizontalAlignment,
    computeValue: @escaping (ViewDimensions) -> CGFloat
    ) -> some View
    alignmentGuide(_:computeValue:)
    • ୈ2Ҿ਺ͷclosure


    • ௐ੔͢Δ஋ʢج४Ґஔ͔ΒͲΕ͘Β͍ͣΒ͔͢ʣΛฦ͢
    طଘ஋ͷ୅ΘΓʹ

    View full-size slide

  44. ϓϨʔϯͳঢ়ଶ == 0
    VStack(alignment:
    .trailing)
    ˞Πϝʔδ

    View full-size slide

  45. .trailingͷσϑΥϧτ஋
    ϓϨʔϯͳঢ়ଶ == 0
    VStack(alignment:
    .trailing)
    ˞Πϝʔδ

    View full-size slide

  46. .trailingͷσϑΥϧτ஋
    .alignmentGuide(.trailing)


    { context in


    context.width * 2


    }

    View full-size slide

  47. .trailingͷσϑΥϧτ஋
    .alignmentGuide(.trailing)


    { context in


    context.width * 2


    }
    طଘ஋Λஔ͖׵͑Δ

    View full-size slide

  48. .trailingͷσϑΥϧτ஋
    .alignmentGuide(.trailing)


    { context in


    context.width * 2


    }
    طଘ஋Λஔ͖׵͑Δ
    .trailingͷσϑΥϧτ஋


    ͷҐஔ͔Β


    Ҡಈ͢Δ༁Ͱ͸ͳ͍

    View full-size slide

  49. ϓϨʔϯͳঢ়ଶ == 0
    .alignmentGuide(.trailing)


    { context in


    context.width * 2


    }
    ˞Πϝʔδ

    View full-size slide

  50. context.width * 2
    ϓϨʔϯͳঢ়ଶ == 0
    .alignmentGuide(.trailing)


    { context in


    context.width * 2


    }
    ˞Πϝʔδ

    View full-size slide

  51. 🙅 .trailingͷσϑΥϧτ஋ ͔Β context.width * 2 ͣΒ͢
    .alignmentGuide(.trailing)


    { context in


    context.width * 2


    }
    🙆 .trailingͷσϑΥϧτ஋ ͔Β context.width * 2 ʹஔ͖׵͑Δ
    VStack(alignment:
    .trailing)

    View full-size slide

  52. func alignmentGuide(
    _ g: HorizontalAlignment,
    computeValue: @escaping (ViewDimensions) -> CGFloat
    ) -> some View
    alignmentGuide(_:computeValue:)
    • ୈ2Ҿ਺ͷclosure


    • ௐ੔ͨ͠஋ʢج४Ґஔ͔ΒͲΕ͘Β͍ͣΒ͔͢ʣΛฦ͢


    • Ҿ਺ͷViewDimensions͔Βར༻Ͱ͖Δ΋ͷ


    • Viewͷwidth, height


    • ֤Alignment GuideҐஔʢoffset஋ʣ

    View full-size slide

  53. 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 }

    View full-size slide

  54. 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 }

    View full-size slide

  55. 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)


    }

    View full-size slide

  56. 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)


    }

    View full-size slide

  57. 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)


    }

    View full-size slide

  58. 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

    View full-size slide

  59. 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)


    }

    View full-size slide

  60. 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͕ࢦఆ͞Ε͍ͯͳ͍ͷͰɺ
    ͜Ε୯ମͰ͸ϨΠΞ΢τʹӨڹ͸ͳ͍

    View full-size slide

  61. 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)


    }

    View full-size slide

  62. 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

    View full-size slide

  63. 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

    View full-size slide

  64. 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 }

    View full-size slide

  65. 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 }

    View full-size slide

  66. 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)


    }

    View full-size slide

  67. 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)


    }

    View full-size slide

  68. 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)


    }
    มԽͳ͠

    View full-size slide

  69. 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

    View full-size slide

  70. 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)


    }

    View full-size slide

  71. 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)


    }

    View full-size slide

  72. 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)


    }

    View full-size slide

  73. 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

    View full-size slide

  74. 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ʣ

    View full-size slide

  75. cf. https://developer.apple.com/documentation/swiftui/view/alignmentguide(_:computevalue:)-9mdoh
    Changing the alignment of one view may have effects
    on surrounding views.

    View full-size slide

  76. 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)

    View full-size slide

  77. 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)

    View full-size slide

  78. 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)

    View full-size slide

  79. ֎ଆͷStackͷframe͕มԽ͠͏Δ

    View full-size slide

  80. ☕ offset(x:y:)

    View full-size slide

  81. 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

    View full-size slide

  82. VStack {


    Text("🐶")


    Text("🐱")


    Text("🐰")


    }


    View full-size slide

  83. VStack {


    Text("🐶")


    Text("🐱")


    .offset(x: 50, y: 100)


    Text("🐰")


    }


    View full-size slide

  84. 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.

    View full-size slide

  85. VStack(spacing: 20) {


    Text("🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰🐰")


    Text("Offset by passing horizontal & vertical distance")


    .border(Color.green)


    .padding()


    }


    .border(.red)


    offset(x:y:)

    View full-size slide

  86. 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:)

    View full-size slide

  87. 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:)

    View full-size slide

  88. 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:)

    View full-size slide

  89. 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:)

    View full-size slide

  90. alignmentGuide(_:computeValue:)


    vs.


    offset(x:y:)

    View full-size slide

  91. alignmentGuide(_:computeValue:)

    View full-size slide

  92. alignmentGuide(_:computeValue:) offset(x:y:)

    View full-size slide

  93. Text("Offset by passing horizontal & vertical distance")


    .border(Color.green)


    .offset(x: 20, y: 50)


    .border(Color.gray)

    View full-size slide

  94. Text("Offset by passing horizontal & vertical distance")


    .border(Color.green)


    .offset(x: 20, y: 50)


    .border(Color.gray)

    View full-size slide

  95. Text("Offset by passing horizontal & vertical distance")


    .border(Color.green)


    .offset(x: 20, y: 50)


    .border(Color.gray)

    View full-size slide

  96. 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)

    View full-size slide

  97. 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)

    View full-size slide

  98. 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)

    View full-size slide

  99. 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)

    View full-size slide

  100. 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)

    View full-size slide

  101. ୈষ
    Custom Alignment Guide

    View full-size slide

  102. 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)


    }

    View full-size slide

  103. extension VerticalAlignment {


    private struct BlueBarTitleAlignment: AlignmentID {


    static func defaultValue(in context: ViewDimensions) -> CGFloat {


    context[.bottom]


    }


    }




    static let blueBarTitleAlignment = VerticalAlignment(


    BlueBarTitleAlignment.self


    )


    }

    View full-size slide

  104. 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)


    }

    View full-size slide

  105. 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)


    }

    View full-size slide

  106. 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)


    }

    View full-size slide

  107. Built-in Alignment Guides

    View full-size slide

  108. 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)


    }

    View full-size slide

  109. 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)


    }

    View full-size slide

  110. 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)


    }

    View full-size slide

  111. 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)


    }
    ࣮ݱ͍ͨ͠ϨΠΞ΢τ

    View full-size slide

  112. alignmentGuide(_:computeValue:)

    View full-size slide

  113. 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)


    }

    View full-size slide

  114. 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)


    }

    View full-size slide

  115. 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)


    }
    มԽͳ͠

    View full-size slide

  116. 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)


    }
    มԽͳ͠

    View full-size slide

  117. 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)


    }
    มԽͳ͠

    View full-size slide

  118. Built-in Alignment Guides


    +


    alignmentGuide(_:computeValue:)
    StackΛ·͍ͨͰViewΛἧ͑Δ͜ͱ͸Ͱ͖ͳ͍

    View full-size slide

  119. 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)


    }

    View full-size slide

  120. 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)


    }

    View full-size slide

  121. 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)


    }
    ̎ͭ໨ͷςΩετʹἧ͑Δͪΐ͏Ͳྑ͍஋ΛฦͤΔ…ʁ

    View full-size slide

  122. Custom Alignment Guide

    View full-size slide

  123. protocol AlignmentID

    View full-size slide

  124. public protocol AlignmentID {


    static func defaultValue(in context: ViewDimensions) -> CGFloat


    }

    View full-size slide

  125. public protocol AlignmentID {


    static func defaultValue(in context: ViewDimensions) -> CGFloat


    }
    HStackͳͲͰࢦఆͨ͠ࡍͷσϑΥϧτ஋

    View full-size slide

  126. private struct BlueBarTitleAlignment: AlignmentID {


    static func defaultValue(in context: ViewDimensions) -> CGFloat {


    context[.bottom]


    }


    }




    View full-size slide

  127. extension VerticalAlignment {


    private struct BlueBarTitleAlignment: AlignmentID {


    static func defaultValue(in context: ViewDimensions) -> CGFloat {


    context[.bottom]


    }


    }




    static let blueBarTitleAlignment = VerticalAlignment(


    BlueBarTitleAlignment.self


    )


    }

    View full-size slide

  128. 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)


    }

    View full-size slide

  129. 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)


    }

    View full-size slide

  130. 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)


    }

    View full-size slide

  131. • StackΛލ͍ͰViewΛἧ͍͑ͨ
    Custom Alignment Guide ͷ࢖͍ॴ

    View full-size slide

  132. • StackΛލ͍ͰViewΛἧ͍͑ͨ


    • alignmentGuide(_:computeValue:) Λ࢖͍ճ͍ͨ͠


    • ViewDimentionsͷ஋͚ͩͰܭࢉͰ͖Δ৔߹
    Custom Alignment Guide ͷ࢖͍ॴ

    View full-size slide

  133. 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)


    }

    View full-size slide

  134. Stack × Custom Alignment Guide


    ͷ ੍໿

    View full-size slide

  135. ̎ϲॴἧ͑

    View full-size slide

  136. VStack(alignment: .profileListRowTextAlignment, spacing: 8) {


    // লུ


    HStack(spacing: 24) {


    Text("ϫΠϯΤΩεύʔτೝఆ൪߸")


    .font(.caption)


    Text("1234567890")


    .font(.caption)


    }


    // লུ


    }


    View full-size slide

  137. VStack(alignment: .profileListRowTextAlignment, spacing: 8) {


    // লུ


    HStack(spacing: 24) {


    Text("ϫΠϯΤΩεύʔτೝఆ൪߸")


    .font(.caption)


    Text("1234567890")


    .font(.caption)


    .alignmentGuide(.profileListRowTextAlignment) {


    $0[.leading] - 30


    }


    }


    // লུʢଞͷTextʹ΋alignmentGuideΛ෇༩ʣ


    }


    View full-size slide

  138. VStack(alignment: .profileListRowTextAlignment, spacing: 8) {


    // লུ


    HStack(spacing: 24) {


    Text("ϫΠϯΤΩεύʔτೝఆ൪߸")


    .font(.caption)


    Text("1234567890")


    .font(.caption)


    .alignmentGuide(.profileListRowTextAlignment) {


    $0[.leading] - 30


    }


    }


    // লུʢଞͷTextʹ΋alignmentGuideΛ෇༩ʣ


    }


    View full-size slide

  139. 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Λ෇༩ʣ


    }


    View full-size slide

  140. 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͝ͱҠಈͤ͞ΔͷͰἧΘͳ͍…

    View full-size slide

  141. • ಉ͡Stack಺ͷෳ਺ͷViewΛἧ͑ΒΕͳ͍


    • ج४ͱͳΔ1ͭͷAlignmentʹରͯ͠ର৅ͷViewΛؚΉStack
    શମͷҐஔΛௐ੔͢Δ࢓૊ΈͷͨΊ
    Stack × Custom Alignment Guide ͷ੍໿

    View full-size slide

  142. 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

    View full-size slide




  143. • frame(width:height:alignment:)


    • frame(minWidth:idealWidth:maxWidth:minHeight:ide
    alHeight:maxHeight:alignment:)

    View full-size slide

  144. 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)

    View full-size slide

  145. 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)

    View full-size slide

  146. Text("""


    ⭐ monoqlo ⭐


    ⭐ iOSDC 2022 ⭐


    """)


    .border(.red)


    View full-size slide

  147. Text("""


    ⭐ monoqlo ⭐


    ⭐ iOSDC 2022 ⭐


    """)


    .border(.red)


    .frame(alignment: .bottom))


    .border(.white)

    View full-size slide

  148. Text("""


    ⭐ monoqlo ⭐


    ⭐ iOSDC 2022 ⭐


    """)


    .border(.red)


    .alignmentGuide(.bottom) {


    $0[.firstTextBaseline]


    }


    .frame(alignment: .bottom))


    .border(.white)

    View full-size slide

  149. VStack {


    Text("top")


    Text("""


    ⭐ monoqlo ⭐


    ⭐ iOSDC 2022 ⭐


    """)


    .border(.red)


    Text("bottom")


    }


    View full-size slide

  150. VStack {


    Text("top")


    Text("""


    ⭐ monoqlo ⭐


    ⭐ iOSDC 2022 ⭐


    """)


    .border(.red)


    Text("bottom")


    }


    .frame(height: 200,


    alignment: .init(horizontal: .center,


    vertical: .frameTextAlignment))


    .border(.white)

    View full-size slide

  151. 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


    )


    }

    View full-size slide

  152. VStack {


    Text("top")


    Text("""


    ⭐ monoqlo ⭐


    ⭐ iOSDC 2022 ⭐


    """)


    .border(.red)


    Text("bottom")


    }


    .frame(height: 200,


    alignment: .init(horizontal: .center,


    vertical: .frameTextAlignment))


    .border(.white)

    View full-size slide

  153. 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)

    View full-size slide

  154. 🤔
    alignmentGuide(_:computeValue:)


    vs.


    offset(x:y:)

    View full-size slide

  155. alignmentGuide(_:computeValue:) offset(x:y:)

    View full-size slide

  156. alignmentGuide(_:computeValue:) offset(x:y:)
    ※ Stackͷalignmentʹରͯ͠࢖ͬͨ࣌

    View full-size slide

  157. • frame(alignment:)


    • frame(minWidth:idealWidth:maxWidth:minHeight:idealHeight:
    maxHeight:alignment:)


    +


    alignmentGuide(_:computeValue:)

    View full-size slide

  158. Alignment Guide


    ೖ໳Ͱ͖ͨͰ͠ΐ͏͔ʁ

    View full-size slide

  159. @monoqloʢ΋ͷ͘Ζʣ
    • 2೥લ͔ΒϦΫϧʔτͷਓ


    • ελσΟαϓϦENGLISH୲౰

    View full-size slide

  160. • 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

    View full-size slide

  161. • 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

    View full-size slide

  162. • Grid


    • https://developer.apple.com/documentation/swiftui/grid


    • Debug


    • https://developer.apple.com/documentation/swiftui/inspecting-view-layout
    Appendix

    View full-size slide