UILabel и UIButton не соблюдают минимальный размер шрифта, несмотря на настройку параметров FontSizeToFitWidth и минимального масштабирования

Я работаю над проектом iOS с использованием Swift и пытаюсь обеспечить, чтобы размер шрифта как в UILabel, так и в UIButton автоматически уменьшался, когда текст не помещался. Однако, несмотря на установку adjustsFontSizeToFitWidth и minimumScaleFactor, размер шрифта, похоже, вообще не меняется.

struct UIStyling {
    static func styleLabel(label: UILabel, textLabel: String) {
        let fontName = "Montserrat-Medium"
        let fontSize: CGFloat = 18
        let minimumFontSize: CGFloat = 6

        guard let font = UIFont(name: fontName, size: fontSize) else {
            fatalError("Failed to load font \(fontName).")
        }

        let kernValue = fontSize * 0.2
        let textColor = UIColor(hex: "FFFFFF")

        label.numberOfLines = 0
        label.textAlignment = .center
        label.lineBreakMode = .byWordWrapping
        label.adjustsFontSizeToFitWidth = true
        label.minimumScaleFactor = minimumFontSize / fontSize

        let labelAttributedString = NSMutableAttributedString(
            string: textLabel,
            attributes: [
                .font: font,
                .kern: kernValue,
                .foregroundColor: textColor
            ]
        )

        label.attributedText = labelAttributedString
    }

    static func styleButton(
        _ button: UIButton,
        title: String,
        fontName: String = "Montserrat-Medium",
        fontSize: CGFloat = 18,
        minimumFontSize: CGFloat = 6,
        cornerRadius: CGFloat = 20,
        backgroundColor: UIColor,
        titleColor: UIColor
    ) {
        guard let font = UIFont(name: fontName, size: fontSize) else {
            fatalError("Failed to load font \(fontName).")
        }

        button.titleLabel?.adjustsFontSizeToFitWidth = true
        button.titleLabel?.minimumScaleFactor = minimumFontSize / fontSize
        button.titleLabel?.numberOfLines = 0
        button.titleLabel?.lineBreakMode = .byClipping

        button.setTitle(title, for: .normal)
        button.titleLabel?.font = font
        button.setTitleColor(titleColor, for: .normal)

        button.backgroundColor = backgroundColor
        button.layer.cornerRadius = cornerRadius
    }
}

func buttonStyles(for sceneType: SceneType) -> (fontName: String, backgroundColors: [(UIColor, UIColor)], textColors: (UIColor, UIColor)) {
    switch sceneType {
    case .egypt:
        return (
            fontName: "Montserrat-Medium",
            backgroundColors: [
                (UIColor(hex: "#FFD700").withAlphaComponent(0.8), UIColor(hex: "#333333")),
                (UIColor(hex: "#006400").withAlphaComponent(0.8), UIColor(hex: "#FFFFFF"))
            ],
            textColors: (UIColor(hex: "#333333"), UIColor(hex: "#FFFFFF"))
        )
    case .future:
        return (
            fontName: "Montserrat-Medium",
            backgroundColors: [
                (UIColor(hex: "#1E90FF").withAlphaComponent(0.8), UIColor(hex: "#FFFFFF")),
                (UIColor(hex: "#D3D0D0").withAlphaComponent(0.8), UIColor(hex: "#090909"))
            ],
            textColors: (UIColor(hex: "#FFFFFF"), UIColor(hex: "#090909"))
        )
    case .main:
        return (
            fontName: "Montserrat-Medium",
            backgroundColors: [
                (UIColor(hex: "#FFD700").withAlphaComponent(0.8), UIColor(hex: "#333333")),
                (UIColor(hex: "#1E90FF").withAlphaComponent(0.8), UIColor(hex: "#FFFFFF"))
            ],
            textColors: (UIColor(hex: "#333333"), UIColor(hex: "#FFFFFF"))
        )
    }
}

func updateUI() {
    let currentScene = storyBrain.getCurrentScene()

    UIStyling.styleLabel(label: textLabel, textLabel: currentScene.title)

    let styles = buttonStyles(for: currentScene.sceneType)

    UIStyling.styleButton(button1,
                          title: currentScene.button1,
                          fontName: styles.fontName,
                          backgroundColor: styles.backgroundColors[0].0,
                          titleColor: styles.textColors.0)

    UIStyling.styleButton(button2,
                          title: currentScene.button2,
                          fontName: styles.fontName,
                          backgroundColor: styles.backgroundColors[1].0,
                          titleColor: styles.textColors.1)

    button1.layer.cornerRadius = Style.cornerRadius
    button2.layer.cornerRadius = Style.cornerRadius

    background.image = UIImage(named: currentScene.backgroundImage)

    print("Label size: \(textLabel.frame.size)")
    print("Minimum scale factor: \(textLabel.minimumScaleFactor)")
    print("Font size: \(textLabel.font.pointSize)")
}
func updateUI() {
    let currentScene = storyBrain.getCurrentScene()

    UIStyling.styleLabel(label: textLabel, textLabel: currentScene.title)

    let styles = buttonStyles(for: currentScene.sceneType)

    UIStyling.styleButton(button1,
                          title: currentScene.button1,
                          fontName: styles.fontName,
                          backgroundColor: styles.backgroundColors[0].0,
                          titleColor: styles.textColors.0)

    UIStyling.styleButton(button2,
                          title: currentScene.button2,
                          fontName: styles.fontName,
                          backgroundColor: styles.backgroundColors[1].0,
                          titleColor: styles.textColors.1)
    
    button1.layer.cornerRadius = Style.cornerRadius
    button2.layer.cornerRadius = Style.cornerRadius

    background.image = UIImage(named: currentScene.backgroundImage)

    print("Label size: \(textLabel.frame.size)")
    print("Minimum scale factor: \(textLabel.minimumScaleFactor)")
    print("Font size: \(textLabel.font.pointSize)")

    // ...
}

Описание проблемы:

  • Проблема: размер шрифта как в UILabel, так и в UIButton не меняется, даже если текст слишком длинный и не помещается.
  • Ожидаемое поведение: если текст не помещается, размер шрифта должен уменьшиться в соответствии с настройкой minimumScaleFactor.
  • Текущее поведение: размер шрифта остается прежним, игнорируя свойства adjustsFontSizeToFitWidth и minimumScaleFactor.

Что я пробовал:

  1. Программная установка adjustsFontSizeToFitWidth и minimumScaleFactor: как показано в приведенном выше коде, я установил эти свойства, но размер шрифта не уменьшается.
  2. Тестирование с разными значениями minimumFontSize: я пробовал разные значения minimumFontSize, но это не имело никакого значения.
  3. Проверка загрузки шрифтов: я подтвердил, что шрифты правильно загружены и применены.
  4. Проверка ограничений автоматического макета: меткам и кнопкам достаточно места, и ограничения кажутся нормальными.

Вопросы:

  1. Почему minimumScaleFactor игнорируется? Есть ли что-то в моем коде, что может помешать этому работать?
  2. Есть ли какой-то конкретный параметр в Interface Builder или программно, который мне может не хватать? Может ли это быть проблемой ограничений?
  3. Может ли это быть связано с ошибкой в ​​целевой версии iOS? Или что-то не так с тем, как я применяю стили?

Среда:

  • Версия Xcode: 15.4 (15F31d)
  • Свифт-версия: 5.10
  • Версия iOS: минимальное количество развертываний — 15.3.

Пожалуйста, покажите минимальный воспроизводимый пример - некоторый код, который я могу вставить в новый проект и воспроизвести проблему.

Sweeper 01.09.2024 10:02

Обычно шрифт не масштабируется с помощью NSAttributedString (или связанных с ним свойств attributedText).

Larme 01.09.2024 12:37
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы получить автоматическое масштабирование шрифта, .lineBreakMode должен быть установлен на отсечение или один из режимов усечения — Head, Middle или (чаще всего) Tail:

//label.lineBreakMode = .byWordWrapping
label.lineBreakMode = .byTruncatingTail
    

Спасибо за помощь! Проблема действительно была в lineBreakMode. После изменения label.lineBreakMode = .byWordWrapping на label.lineBreakMode = .byTruncatingTail автоматическое масштабирование шрифтов начало работать правильно. Теперь все работает отлично. Еще раз спасибо за дельный совет!

Артур Рыбчук 04.09.2024 14:58

Другие вопросы по теме