Swift — невозможно выровнять элементы стека с разными размерами шрифта

#swift #uiview #uistackview

#swift #uiview #uistackview

Вопрос:

У меня есть 2 UILabels следующим образом:

 private lazy var titleLabel: UILabel = {
    let label = UILabel()
    label.textColor = Constants.mainFontColor.withAlphaComponent(0.7)
    label.translatesAutoresizingMaskIntoConstraints = false
    label.isUserInteractionEnabled = false
    label.sizeToFit()
    return label
}()

private lazy var valueLabel: UILabel = {
    let label = UILabel()
    label.textColor = Constants.mainFontColor
    label.translatesAutoresizingMaskIntoConstraints = false
    label.isUserInteractionEnabled = false
    label.sizeToFit()
    return label
}()
  

Затем эти метки помещаются в UIStackView:

 private lazy var stackView: UIStackView = {
    let stack = UIStackView(arrangedSubviews: [titleLabel, valueLabel])
    stack.translatesAutoresizingMaskIntoConstraints = false
    stack.axis = .horizontal
    stack.spacing = 5
    stack.alignment = .firstBaseline
    addSubview(stack)
    return stack
}()
  

Затем я создаю несколько таких экземпляров, например:

 private lazy var flightNumber: FuelSheetHeaderField = {
    return FuelSheetHeaderField(title: FuelSheetStringsField.flightNumber.title.localized,
                                value: viewModel.flightNumber, titleFontSize: 17, valueFontSize: 24)
}()
  

Затем они помещаются в отдельный вид стека:

    private lazy var flightData: UIStackView = {
        let stack = UIStackView(arrangedSubviews: [flightNumber, aircraftReg, dateTime, origin])
        stack.axis = .horizontal
        stack.distribution = .equalSpacing
        stack.spacing = Constants.standardHorizontalStackSpacing
        return stack
    }()
  

Размер шрифта заголовков равен 12, а значения имеют размер шрифта 17. За исключением одного, который настроен на размер шрифта 17 и 2 соответственно. Я пытаюсь выровнять все элементы по одной базовой линии. Я добавил следующее ограничение:

 titleLabel.firstBaselineAnchor.constraint(equalTo: valueLabel.firstBaselineAnchor),
  

Однако эффект заключается в следующем:

введите описание изображения здесь

Большинство элементов стека выравниваются, но, как вы можете видеть, первый элемент с более крупным шрифтом расположен выше второго. Это немного сводит меня с ума. Как я могу это исправить, чтобы все элементы в стеке выравнивались по одной и той же базовой линии.

Ответ №1:

Я думаю, у вас возникнут проблемы при попытке использовать базовые показатели в представлениях стека.

Один из вариантов — не уверен, что он будет работать для вас — это поместить все метки в один горизонтальный вид стека и использовать .setCustomSpacing() для настройки пробелов между метками.

В качестве примера:

введите описание изображения здесь

и с Debug -> View Debugging -> Show View Frames :

введите описание изображения здесь

Вот код, который я использовал для создания этого:

 class AlignedStackViewController: UIViewController {

    let detailsStack: UIStackView = {
        let v = UIStackView()
        v.axis = .vertical
        v.alignment = .leading
        v.distribution = .fill
        v.spacing = 12
        return v
    }()
    
    let dataStack: UIStackView = {
        let v = UIStackView()
        v.axis = .horizontal
        v.alignment = .firstBaseline
        v.distribution = .fill
        v.spacing = 5
        return v
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor(red: 0.928, green: 0.973, blue: 1.0, alpha: 1.0)

        let fdLabel = UILabel()
        fdLabel.text = "FLIGHT DETAILS"
        
        detailsStack.addArrangedSubview(fdLabel)
        detailsStack.addArrangedSubview(dataStack)
        
        detailsStack.translatesAutoresizingMaskIntoConstraints = false
        
        view.addSubview(detailsStack)
        
        // respect safe area
        let g = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            // position stack view at 40, 100
            detailsStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
            detailsStack.topAnchor.constraint(equalTo: g.topAnchor, constant: 100.0),
        ])
        
        addLabelPair(with: "#", value: "VS0105", titleFontSize: 17, valueFontSize: 24)
        addLabelPair(with: "Reg:", value: "GAAAA", titleFontSize: 12, valueFontSize: 17)
        addLabelPair(with: "Departure:", value: "09 Sep 2020", titleFontSize: 12, valueFontSize: 17)
        addLabelPair(with: "at", value: "08:34", titleFontSize: 12, valueFontSize: 17)

        updateStackSpacing()

    }
    
    func updateStackSpacing() -> Void {
        // make sure stack has been filled
        guard dataStack.arrangedSubviews.count == 8 else {
            return
        }
        // verbose for clarity
        let flightNumberLabel = dataStack.arrangedSubviews[1]
        let aircraftRegLabel = dataStack.arrangedSubviews[3]
        dataStack.setCustomSpacing(12, after: flightNumberLabel)
        dataStack.setCustomSpacing(12, after: aircraftRegLabel)
    }
    
    func addLabelPair(with title: String, value: String, titleFontSize: CGFloat, valueFontSize: CGFloat) -> Void {
        
        let tLabel = UILabel()
        let vLabel = UILabel()
        
        tLabel.font = UIFont.systemFont(ofSize: titleFontSize)
        vLabel.font = UIFont.systemFont(ofSize: valueFontSize)
        
        tLabel.textColor = UIColor.black.withAlphaComponent(0.7)
        vLabel.textColor = UIColor.black

        tLabel.text = title
        vLabel.text = value
        
        dataStack.addArrangedSubview(tLabel)
        dataStack.addArrangedSubview(vLabel)
        
    }

}
  

Ответ №2:

Я думаю, кажется, что UILabel имеет заполнение по умолчанию

А значение отступа по умолчанию зависит от размера шрифта.

Несмотря на sizeToFit , результат тот же

введите описание изображения здесь