Search code examples
uitextfieldswift4nsattributedstring

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


I have three UITextFields that will only contain a whole number between 0 and either 13066 or 3915 maximum. It's presented with a special font where font1 at 50pt is larger than font2 at 50pt so I only need to play around with the font file, not the size.

1) I need help finding a way to have the hundreds presented with font2 but when the number >= 1000, the digits for thousands is presented with font1, while the hundreds still maintain font2. As this is a UITextField input, I need this to happen real-time.

Animated picture of how the end result eventually will be!

2) If you watch the animation, you'll see that each of the three fields totals to the field at the bottom. This is straight forward. However, I also want to reverse this, i.e filling in the total and the dials and digits should fill in as shown (half in each MAIN up to 3920 and remaining in CTR up to 13066). How do I code a functioning reversible calculation like that and avoid conflict?

This is what I got so far but it doesn't quite do what I want yet:

`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
}

Solution

  • Use 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
    }
    

    Then set the attributedText property on your label:

    label.attributedText = getAttributedString(for: 13006)
    

    And you can get result like this:

    big number

    Adjust the styles to taste!