如何实现两个UILabel基于第一行文本Y轴中心对齐(含SwiftUI方案)
解决方案:UILabel 第一行文本Y轴中心对齐
UIKit 实现方案
核心思路是计算每个Label第一行文本的中心偏移量,通过调整顶部约束让两个Label的第一行中心处于同一Y轴位置,适配任意字体字号。
关键步骤:
- 利用字体的
ascender(基线到字符顶部距离,正数)和descender(基线到字符底部距离,负数),计算第一行文本中心相对于Label顶部的偏移量 - 动态调整两个Label的顶部约束常量,补偿偏移实现对齐
代码实现:
import UIKit class FirstLineAlignedLabelsView: UIView { let label1 = UILabel() let label2 = UILabel() override init(frame: CGRect) { super.init(frame: frame) setupBasicViews() setupLayoutConstraints() } required init?(coder: NSCoder) { super.init(coder: coder) setupBasicViews() setupLayoutConstraints() } private func setupBasicViews() { label1.numberOfLines = 0 label2.numberOfLines = 0 addSubview(label1) addSubview(label2) label1.translatesAutoresizingMaskIntoConstraints = false label2.translatesAutoresizingMaskIntoConstraints = false } private func setupLayoutConstraints() { // 基础布局约束 let baseConstraints = [ label1.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16), label2.leadingAnchor.constraint(equalTo: label1.trailingAnchor, constant: 16), label2.trailingAnchor.constraint(lessThanOrEqualTo: trailingAnchor, constant: -16), bottomAnchor.constraint(greaterThanOrEqualTo: label1.bottomAnchor, constant: 16), bottomAnchor.constraint(greaterThanOrEqualTo: label2.bottomAnchor, constant: 16) ] // 计算第一行中心偏移并设置顶部约束 let offset1 = getFirstLineCenterOffset(for: label1.font) let offset2 = getFirstLineCenterOffset(for: label2.font) let topConstraints = [ label1.topAnchor.constraint(equalTo: topAnchor, constant: -offset1), label2.topAnchor.constraint(equalTo: topAnchor, constant: -offset2) ] NSLayoutConstraint.activate(baseConstraints + topConstraints) } private func getFirstLineCenterOffset(for font: UIFont) -> CGFloat { // 第一行文本中心相对于Label顶部的偏移量 let lineHeight = font.ascender - font.descender let centerFromTop = lineHeight / 2 - font.ascender return centerFromTop } // 动态更新文本和字体时调用 func updateContent(text1: String, font1: UIFont, text2: String, font2: UIFont) { label1.text = text1 label1.font = font1 label2.text = text2 label2.font = font2 // 更新偏移量和约束 let offset1 = getFirstLineCenterOffset(for: font1) let offset2 = getFirstLineCenterOffset(for: font2) label1.constraints.first { $0.firstAnchor == label1.topAnchor }?.constant = -offset1 label2.constraints.first { $0.firstAnchor == label2.topAnchor }?.constant = -offset2 layoutIfNeeded() } }
SwiftUI 实现方案
通过自定义垂直对齐指南,结合字体属性计算第一行文本中心位置,实现灵活对齐。
代码实现:
import SwiftUI struct FirstLineAlignedTextPair: View { let text1: String let font1: Font let text2: String let font2: Font var body: some View { HStack(alignment: .firstLineCenter, spacing: 16) { Text(text1) .font(font1) .alignmentGuide(.firstLineCenter) { dims in calculateAlignmentOffset(for: dims, font: font1) } Text(text2) .font(font2) .alignmentGuide(.firstLineCenter) { dims in calculateAlignmentOffset(for: dims, font: font2) } } .padding(16) } private func calculateAlignmentOffset(for dims: ViewDimensions, font: Font) -> CGFloat { guard let uiFont = UIFont(font: font) else { return dims[.firstBaseline] / 2 } let lineHeight = uiFont.ascender - uiFont.descender let centerFromBaseline = lineHeight / 2 return dims[.firstBaseline] - centerFromBaseline } } // 自定义第一行中心对齐指南 extension VerticalAlignment { private enum FirstLineCenter: AlignmentID { static func defaultValue(in context: ViewDimensions) -> CGFloat { context[.top] } } static let firstLineCenter = VerticalAlignment(FirstLineCenter.self) } // SwiftUI Font 转 UIFont 扩展 extension UIFont { convenience init?(font: Font) { let descriptor = font.fontDescriptor self.init(descriptor: descriptor, size: descriptor.pointSize) } } // 预览示例 struct FirstLineAlignedTextPair_Previews: PreviewProvider { static var previews: some View { FirstLineAlignedTextPair( text1: "小字号文本", font1: .caption, text2: "大字号文本\n支持多行自动换行\n内容动态变化", font2: .title ) } }
内容的提问来源于stack exchange,提问作者memical
相关产品推荐
相关产品推荐

