创建具有动态字体大小的UIButton,但是所有UIButton在UIStackView中共享相同的字体大小

时间:2019-07-05 17:39:18

标签: swift xcode uibutton autolayout uistackview

我正在使用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)
}

image

1 个答案:

答案 0 :(得分:0)

您可以尝试使用此功能来返回标签的缩放字体大小:

    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不一定会给您 exact 点大小。另外,由于这会更改分配给标签的实际字体大小,因此,如果动态更改按钮标题,则需要进行一些重置。可能还需要考虑按钮框架的变化(例如随着设备旋转等)。

但是...这是一个快速测试,您可以运行该测试以查看方法:

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