SwiftUI Text неожиданные отступы снизу и сверху

Мне нужен точный контроль над областью, занимаемой текстом. Я создал самую простую программу, которая показывает неожиданные верхние и нижние интервалы, добавляемые к тексту. Откуда эта дополнительная набивка? Как от этого избавиться?

@mainstruct myApp: App {

      init() {    }

var body: some Scene {
    WindowGroup {
        Text("80")
            .font(.system(size: 30, weight: .bold, design: .default))
            .background(Color.red)
    }
}

}

3 ответа

Решение

Кажется, что у текста есть отступы по умолчанию, как показано здесь

Вы можете обойти это, настроив отступ на отрицательное значение.

Замените свой код этим

      Text("80")
        .font(.system(size: 30, weight: .bold, design: .default))
        .padding(.vertical, -6)
        .background(Color.red)

Вот решение, если вы хотите сделать его динамичным

        struct TestView: View {
    var fontSize: CGFloat = 110
    var paddingSize: CGFloat {
        -(fontSize * 0.23)
    }
    var body: some View {
        Text("80")
            .font(.system(size: fontSize, weight: .bold, design: .default))
            .padding(.vertical, paddingSize)
            .background(Color.red)
        Text("Hello")
    }
}

Таким образом, даже с большим размером шрифта 110, как на картинке, вы можете отобразить его так, как вам нравится.

Вам нужно будет настроить множитель по своему усмотрению.

Оказывается, обивки сверху и снизу на самом деле нет вообще. В моем примере с числами это выглядит как потраченное впустую пространство, но на самом деле некоторым персонажам действительно нужна эта комната, как видно на этой картинке:

Поскольку я собираюсь показывать только числа, я использовал решение @Sergio, чтобы исправить это превышение.

Для всех, кто все еще борется с этим, позвольте мне добавить свой подход в список. Я знаю, что это не пустая трата места, учитывая такие символы, как Ö и g, но при разработке с сеткой вы обычно хотите использовать высоту прописной буквы шрифта.

Мой подход все еще немного хакерский, но я не хотел использовать магические числа. Хитрость заключается в том, что с помощьюboundingRectСтроковая функция, вы можете получить точную высоту одной строки текста, включая отступы:

      let uiFont = UIFont.systemFont(ofSize: 40, weight: .semibold)

let heightOfOneLine = "X".boundingRect(
    with: CGSize(width: CGFloat(10), height: .greatestFiniteMagnitude),
    options: .usesLineFragmentOrigin,
    attributes: [.font: uiFont],
    context: nil
).size.height

Вы можете использовать это, чтобы затем вычислить вертикальный отступ на основе высоты шапки шрифта:

      let padding = (heightOfOneLine - uiFont.capHeight) / 2

Это вертикальный отступ, который вам нужно вычесть, чтобы получить область с точно такой же высотой:

      .padding(.vertical, -padding)

Убедитесь, что либо используете для своего текста, преобразовав его в a, либо создайте с теми же свойствами. Жаль, что до сих пор нет возможности выбраться изFontи что вы можете использовать толькоUIFontдля этих вычислений.

Вы можете протестировать все это, используя следующий вид:

      struct TestView: View {
    private let uiFont = UIFont.systemFont(ofSize: 200, weight: .semibold)

    var body: some View {
        Text("X")
            .font(Font(uiFont))
            .padding(.vertical, -getPadding())
            .background(.red)
    }

    private func getPadding() -> CGFloat {
        let heightOfOneLine = "X".boundingRect(
            with: CGSize(width: CGFloat(10), height: .greatestFiniteMagnitude),
            options: .usesLineFragmentOrigin,
            attributes: [.font: uiFont],
            context: nil
        ).size.height

        return (heightOfOneLine - uiFont.capHeight) / 2
    }
}
Другие вопросы по тегам