Custom Alignment within ZStack

💡 雖然下面的例子使用自製對齊線,但討論區裡的做法可能比較快。

/// ⭐️ 1. define custom vertical alignment (for cap height)
extension VerticalAlignment {
    private struct CapHeightAlignment: AlignmentID {
        static func defaultValue(in context: ViewDimensions) -> CGFloat {
            context[VerticalAlignment.firstTextBaseline]
        }
    }
    static let capHeight = VerticalAlignment(
        CapHeightAlignment.self
    )
}

/// ⭐️ 2. define custom horizontal alignment (for "second" leading)
extension HorizontalAlignment {
    private struct SecondLeadingAlignment: AlignmentID {
        static func defaultValue(in context: ViewDimensions) -> CGFloat {
            context[.leading]
        }
    }
    static let secondLeading = HorizontalAlignment(
        SecondLeadingAlignment.self
    )
}

struct View1: View {
    
    /// ⭐️ Unfortunately, we still have to use `UIFont`
    ///    to access the `.capHeight` property.
    let bigFont = UIFont.systemFont(ofSize: 70)
    let smallFont = UIFont.systemFont(ofSize: 24)
    
    var body: some View {
        
        /// ⭐️ ZStack 內部使用自製的對齊線
        ZStack(alignment: Alignment(
            horizontal: .secondLeading, vertical: .capHeight
        )) {
            
            /// HStack 內部以 `.firstTextBaseline` 排版,
            /// "7" 與 "kts" 底線對齊。
            HStack(alignment: .firstTextBaseline, spacing: 3) {
                
                Text("7")
                    .font(.system(size: 70))
                    .foregroundColor(Color.green)
                    /// ⭐️ "7" 與 ".0" 垂直方向以 `.capHeight` 對齊
                    .alignmentGuide(.capHeight) { dim in
                        // ⭐️ 但必須手動調整 `.capHeight` 對齊線的位置。
                        dim[.firstTextBaseline] - bigFont.capHeight
                    }
                
                    Text("kts")
                        .font(.system(size: 18))
                        /// ⭐️ "kts" 與 ".0" 水平方向以 `.secondLeading` 對齊
                        .alignmentGuide(.secondLeading) { $0[.leading] }
            }.baseLine(color: .blue)
            

            Text(".0")
                .font(.system(size: 24))
                .foregroundColor(Color.green)
                /// ⭐️ "kts" 與 ".0" 水平方向以 `.secondLeading` 對齊
                .alignmentGuide(.secondLeading){ $0[.leading] }
                /// ⭐️ "7" 與 ".0" 垂直方向以 `.capHeight` 對齊
                .alignmentGuide(.capHeight) { dim in
                    // ⭐️ 但必須手動調整 `.capHeight` 對齊線的位置。
                    dim[.firstTextBaseline] - smallFont.capHeight
                }

        }.overlay(HLine(), alignment: Alignment(
            horizontal: .center, vertical: .capHeight
        )).overlay(VLine(), alignment: Alignment(
            horizontal: .secondLeading, vertical: .center
        ))
    }
}

Last updated