Создание UIB-кнопок с динамическим размером шрифта, но все они имеют одинаковый размер шрифта в UIStackView - PullRequest
0 голосов
/ 05 июля 2019

Я использую UIStackView и добавляю к нему три кнопки.Я хочу, чтобы кнопка с наибольшим количеством текста (B1) была автоматически изменена в соответствии с шириной, а остальные кнопки будут иметь тот же размер шрифта, что и B1.

@IBOutlet weak var stackView: UIStackView!

var btnTitles = [String]()
btnTitles.append("Practice Exams")
btnTitles.append("Test Taking Tips")
btnTitles.append("About")
createButtons(buttonTitles: btnTitles)

var min = CGFloat(Int.max) // keep track of min font

func createButtons(buttonTitles: [String]) {

    var Buttons = [UIButton]()

    for title in buttonTitles {
        let button = makeButtonWithText(text: title)
        // set the font to dynamically size
        button.titleLabel!.numberOfLines = 1
        button.titleLabel!.adjustsFontSizeToFitWidth = true
        button.titleLabel!.baselineAdjustment = .alignCenters // I think it keeps it centered vertically
        button.contentEdgeInsets = UIEdgeInsetsMake(5, 10, 5, 10); // set margins
        if (button.titleLabel?.font.pointSize)! < min {
            min = (button.titleLabel?.font.pointSize)! // to get the minimum font size of any of the buttons
        }

        stackView.addArrangedSubview(button)
        Buttons.append(button)
    }
}

func makeButtonWithText(text:String) -> UIButton {
    var myButton = UIButton(type: UIButtonType.system)
    //Set a frame for the button. Ignored in AutoLayout/ Stack Views
    myButton.frame = CGRect(x: 30, y: 30, width: 150, height: 100)
    // background color - light blue
    myButton.backgroundColor = UIColor(red: 0.255, green: 0.561, blue: 0.847, alpha: 1)

    //State dependent properties title and title color
    myButton.setTitle(text, for: UIControlState.normal)
    myButton.setTitleColor(UIColor.white, for: UIControlState.normal)

    // set the font to dynamically size
    myButton.titleLabel!.font = myButton.titleLabel!.font.withSize(70)
    myButton.contentHorizontalAlignment = .center // align center

    return myButton
}

Я хотел найти минимумразмер шрифта, а затем установите все кнопки на минимум в кнопке viewDidAppear, шрифт печатается как 70 для всех из них, даже если они явно выглядят разных размеров (см. изображение)

override func viewDidAppear(_ animated: Bool) {
    print("viewDidAppear")

    let button = stackView.arrangedSubviews[0] as! UIButton
    print(button.titleLabel?.font.pointSize)
    let button1 = stackView.arrangedSubviews[1] as! UIButton
    print(button1.titleLabel?.font.pointSize)
    let button2 = stackView.arrangedSubviews[2] as! UIButton
    print(button2.titleLabel?.font.pointSize)
}

изображение

1 Ответ

0 голосов
/ 09 июля 2019

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

    func actualFontSize(for aLabel: UILabel) -> CGFloat {

        // label must have text, must have .minimumScaleFactor and must have .adjustsFontSizeToFitWidth == true
        guard let str = aLabel.text,
            aLabel.minimumScaleFactor > 0.0,
            aLabel.adjustsFontSizeToFitWidth
            else { return aLabel.font.pointSize }

        let attributes = [NSAttributedString.Key.font : aLabel.font]
        let attStr = NSMutableAttributedString(string:str, attributes:attributes as [NSAttributedString.Key : Any])

        let context = NSStringDrawingContext()
        context.minimumScaleFactor = aLabel.minimumScaleFactor

        _ = attStr.boundingRect(with: aLabel.bounds.size, options: .usesLineFragmentOrigin, context: context)

        return aLabel.font.pointSize * context.actualScaleFactor

    }

На viewDidAppear() вы бы перебирали кнопки, получая наименьший фактический размер шрифта, а затем устанавливали размер шрифта для каждой кнопки на это значение.

Это потребует некоторых экспериментов ... Во-первых, в прошлом я заметил, что размеры шрифтов могут округляться - поэтому установка размера шрифта метки на 20.123456789 не обязательно даст вам точное значение размер точки. Кроме того, так как это изменяет фактический размер шрифта, назначенный меткам, вам нужно будет выполнить некоторый сброс, если вы динамически изменяете заголовок кнопки. Вероятно, также необходимо учитывать изменения кадров кнопок (например, при повороте устройства и т. Д.).

Но ... вот быстрый тест, который вы можете запустить, чтобы увидеть подход:

class TestViewController: UIViewController {

    let stackView: UIStackView = {
        let v = UIStackView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.axis = .vertical
        v.alignment = .center
        v.distribution = .fillEqually
        v.spacing = 8
        return v
    }()

    var btnTitles = [String]()
    var theButtons = [UIButton]()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        fixButtonFonts()
    }

    func setupUI() -> Void {

        view.addSubview(stackView)

        NSLayoutConstraint.activate([
            stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 40),
            stackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 40),
            stackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -40),
            ])

        btnTitles.append("Practice Exams")
        btnTitles.append("Test Taking Tips")
        btnTitles.append("About")
        createButtons(buttonTitles: btnTitles)

    }

    func fixButtonFonts() -> Void {

        var minActual = CGFloat(70)

        // get the smallest actual font size
        theButtons.forEach { btn in
            if let lbl = btn.titleLabel {
                let act = actualFontSize(for: lbl)
                // for debugging
                //print("actual font size: \(act)")
                minActual = Swift.min(minActual, act)
            }
        }

        // set font size for each button
        theButtons.forEach { btn in
            if let lbl = btn.titleLabel {
                lbl.font = lbl.font.withSize(minActual)
            }
        }

    }

    func createButtons(buttonTitles: [String]) {

        for title in buttonTitles {
            let button = makeButtonWithText(text: title)
            // set the font to dynamically size
            button.titleLabel!.numberOfLines = 1
            button.titleLabel!.adjustsFontSizeToFitWidth = true
            // .minimumScaleFactor is required
            button.titleLabel!.minimumScaleFactor = 0.05
            button.titleLabel!.baselineAdjustment = .alignCenters // I think it keeps it centered vertically
            button.contentEdgeInsets = UIEdgeInsets(top: 5, left: 10, bottom: 5, right: 10); // set margins

            stackView.addArrangedSubview(button)
            theButtons.append(button)
        }

    }

    func makeButtonWithText(text:String) -> UIButton {
        let myButton = UIButton(type: UIButton.ButtonType.system)
        //Set a frame for the button. Ignored in AutoLayout/ Stack Views
        myButton.frame = CGRect(x: 30, y: 30, width: 150, height: 100)
        // background color - light blue
        myButton.backgroundColor = UIColor(red: 0.255, green: 0.561, blue: 0.847, alpha: 1)

        //State dependent properties title and title color
        myButton.setTitle(text, for: UIControl.State.normal)
        myButton.setTitleColor(UIColor.white, for: UIControl.State.normal)

        // set the font to dynamically size
        myButton.titleLabel!.font = myButton.titleLabel!.font.withSize(70)
        myButton.contentHorizontalAlignment = .center // align center

        return myButton
    }

    func actualFontSize(for aLabel: UILabel) -> CGFloat {

        // label must have text, must have .minimumScaleFactor and must have .adjustsFontSizeToFitWidth == true
        guard let str = aLabel.text,
            aLabel.minimumScaleFactor > 0.0,
            aLabel.adjustsFontSizeToFitWidth
            else { return aLabel.font.pointSize }

        let attributes = [NSAttributedString.Key.font : aLabel.font]
        let attStr = NSMutableAttributedString(string:str, attributes:attributes as [NSAttributedString.Key : Any])

        let context = NSStringDrawingContext()
        context.minimumScaleFactor = aLabel.minimumScaleFactor

        _ = attStr.boundingRect(with: aLabel.bounds.size, options: .usesLineFragmentOrigin, context: context)

        return aLabel.font.pointSize * context.actualScaleFactor

    }

}

Результат:

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...