Swift 4:当.count > 3时,如何改变多个UITextFields中数字的字体属性,如何反向计算?

Swift 4: How to change font attributes of number in multiple UITextFields when .count > 3 and how to reverse calculation?

我有三个 UITextField,它们只包含一个介于 0 和最大 13066 或 3915 之间的整数。它带有一种特殊字体,其中 50pt 处的 font1 大于 50pt 处的 font2,所以我只需要调整字体文件,而不是大小。

1) 我需要帮助找到一种方法,让数百位显示为 font2,但是当数字 >= 1000 时,千位数字显示为 font1,而数百人仍然保持font2。由于这是一个 UITextField 输入,我需要它实时发生。

Animated picture of how the end result eventually will be!

2) 如果您观看动画,您会看到三个字段中的每一个的总和都等于底部的字段。这是直截了当的。然而,我也想扭转这一点,即填写总数,表盘和数字应如图所示填写(每个 MAIN 中的一半高达 3920,其余在 CTR 中高达 13066)。我如何编写这样的功能可逆计算并避免冲突?

这是我目前得到的结果,但还不能完全满足我的要求:

`class ViewController: UIViewController, UITextFieldDelegate {

@IBOutlet weak var centerField: UITextField!
@IBOutlet weak var main1Field: UITextField!
@IBOutlet weak var main2Field: UITextField!
@IBOutlet weak var totalField: UITextField!


override func viewDidLoad() {
    super.viewDidLoad()

    //UITextField delegation
    centerField.delegate = self
    main1Field.delegate = self
    main2Field.delegate = self
    totalField.delegate = self

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

//Change font when number input exceeds 3 digits
func getAttributedString(for number: Int) -> NSAttributedString {
    let defaultAttributes = [
        NSAttributedStringKey.font: UIFont(name: "PMDG_777_DU_A", size: UIFont.labelFontSize)!
    ]
    let bigNumberAttributes = [
        NSAttributedStringKey.font: UIFont(name: "PMDG_777_DU_B", size: UIFont.labelFontSize)!
    ]

    let attributedString = NSMutableAttributedString(string: "\(number)", attributes: defaultAttributes)
    if attributedString.length > 3 {
        let substr = attributedString.string.dropLast(3)
        let range = NSMakeRange(0, substr.utf16.count)
        attributedString.setAttributes(bigNumberAttributes, range: range)
    }

    return attributedString
}

//Hide keyboard when hitting Return
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    return true
}

//Hide keyboard when tapping outside of field
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    self.view.endEditing(true)
}

//Real-time calculation of entries made to the fields and output it live to the total
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    //Convert the String inserted into the fields into Int and create variables
    let centerFuel = Int(centerField.text!) ?? 0
    centerField.attributedText = getAttributedString(for: centerFuel)
    let main1Fuel = Int(main1Field.text!) ?? 0
    main1Field.attributedText = getAttributedString(for: main1Fuel)
    let main2Fuel = Int(main2Field.text!) ?? 0
    main2Field.attributedText = getAttributedString(for: main2Fuel)

    let total: Int = centerFuel + main1Fuel + main2Fuel
    totalField.attributedText = getAttributedString(for: total)
    return true
}

这是一个示例解决方案:

func attributedString(fromIntStr: String) -> NSAttributedString {
    print("Working with: \(fromIntStr)")

    let finalAttr = NSMutableAttributedString.init()

    let length = fromIntStr.count
    if length > 3 //we test this because we can't do dropLast(n) where n is negative
    {
        let start = String(fromIntStr.dropLast(3))

        let firstPart = NSAttributedString.init(string: start,
                                                attributes: [.font: UIFont.systemFont(ofSize: 20)])
        finalAttr.append(firstPart)
    }

    var dropEnd = 0
    if length > 3 //we test this because we can't do dropFirst(n) where n is negative
    {
        dropEnd = length - 3
    }
    else
    {
        dropEnd = 0 //That's just an explicit value but it was already set by default
    }
    let end = String(fromIntStr.dropFirst(dropEnd))


    let lastPart = NSAttributedString.init(string: end,
                                           attributes: [.font: UIFont.systemFont(ofSize: 15)])

    finalAttr.append(lastPart)

    //It seems that you want a right alignement and since we are using NSAttributedString we can do it by using ParagraphStyle
    let paragraphStyle = NSMutableParagraphStyle.init()
    paragraphStyle.alignment = .right
    finalAttr.addAttribute(.paragraphStyle,
                           value: paragraphStyle,
                           range: NSRange(location: 0, length: finalAttr.length))

    return finalAttr
}

可以在 Playground 上测试,最后添加:

let values = ["", "9", "89", "789", "6789", "56789"]

let view = UIView.init(frame: CGRect(x: 0, y: 0, width: 800, height: 400))

for (i, str) in values.enumerated().reversed()
{
    let label = UILabel.init(frame: CGRect(x: 0, y: i*50, width: 800, height: 50))
    let attr = attributedString(fromIntStr: str)
    label.attributedText = attr
    view.addSubview(label)
}

view

有多种方法可以做到这一点,但这是我使用的逻辑: • 创建 NSMutableAttributedString.
• 将字符串分成两个字符串(一个用于0-999,另一个用于其余部分)
• 用相应的字体
从中创建两个 NSAttributedString • 将它们附加到之前创建的 NSMutableAttributedString

当然可以改进:
dropFirst()/dropLast() 是最好的解决方案吗?
我假设您已经从 Int 添加了一个 String 值(我没有进行转换)。

另一个更经典的解决方案是:
• 从整个 String.
创建一个 NSMutableAttributedString • 在范围 last from last-3
上应用小字体 • 在范围开始到最后应用大字体 -3

如果您在整个字符串的开头应用大字体,则最后一点将被省略。

使用NSMutableAttributedString:

func getAttributedString(for number: Int) -> NSAttributedString {
    precondition(number >= 0)

    let defaultAttributes = [
        NSAttributedStringKey.font: UIFont.systemFont(ofSize: 18)
    ]
    let bigNumberAttributes = [
        NSAttributedStringKey.font: UIFont.systemFont(ofSize: 30)
    ]

    let attributedString = NSMutableAttributedString(string: "\(number)", attributes: defaultAttributes)
    if attributedString.length > 3 {
        let range = NSMakeRange(0, attributedString.length - 3)
        attributedString.setAttributes(bigNumberAttributes, range: range)
    }

    return attributedString
}

然后在你的标签上设置attributedText 属性:

label.attributedText = getAttributedString(for: 13006)

你可以得到这样的结果:

根据口味调整样式!