15

I use typingAttributes to set a new font. On iOS 10, everything works, but on iOS 11, first typed character is correct, but then attributes are being reset to the previous ones, and the second character is typed with the previous font. Is this a bug? Can I fix it somehow?

Mohammad Anini
  • 5,073
  • 4
  • 35
  • 46
Bartosz Bialecki
  • 4,391
  • 10
  • 42
  • 64

5 Answers5

11

Why this happened:

Apple updated typingAttributes since iOS 11

This dictionary contains the attribute keys (and corresponding values) to apply to newly typed text. When the text view’s selection changes, the contents of the dictionary are cleared automatically.

How to fix it:

@Serdnad's code works but it will skip the first character. Here is my finding after trying everything that I can possibly think of

1. If you just want one universal typing attribute for your text view

Simply set the typing attribute once in this delegate method and you are all set with this single universal font

func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
    //Set your typing attributes here
    textView.typingAttributes = [NSAttributedStringKey.foregroundColor.rawValue: UIColor.blue, NSAttributedStringKey.font.rawValue: UIFont.systemFont(ofSize: 17)]
    return true
}

enter image description here

2. In my case, a Rich Text Editor with attributes changeinge all the times:

In this case, I do have to set typing attributes each and every time after entering anything. Thank you iOS 11 for this update!

However, instead of setting that in textViewDidChange method, doing it in shouldChangeTextIn method works better since it gets called before entering characters into the text view.

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    textView.typingAttributes = [NSAttributedStringKey.foregroundColor.rawValue: UIColor.blue, NSAttributedStringKey.font.rawValue: UIFont.systemFont(ofSize: 17)]
    return true
}

enter image description here

Community
  • 1
  • 1
Fangming
  • 24,551
  • 6
  • 100
  • 90
  • @user2296278 Sadly, I have removed the editor.... It won't work since the html generated by iOS from attributted text is not usable on Android devices – Fangming Feb 08 '18 at 17:21
  • 1
    ok thanks I want this editor because I can't find any text editor in swift 4 if you recreated or use GitHub or you can help me send me a message please – user2296278 Feb 08 '18 at 17:47
  • 1
    We're solving it through a sort of Hack. See: https://github.com/wordpress-mobile/AztecEditor-iOS/blob/develop/Aztec/Classes/TextKit/TextView.swift#L580 – diegoreymendez Mar 19 '18 at 15:30
  • Be careful, this solution doesn't work for iOS12 and "Automatic Strong Passwords". The app just freezes forever – iWheelBuy Jun 27 '19 at 12:28
  • **while this old answer has critical and awesome information, unfortunately many details have changed. I've put in a new answer for 2023** – Fattie Apr 12 '23 at 15:13
9

Had issues with memory usage while using typingAttributes

This solution worked:

textField.defaultTextAttributes = yourAttributes // (set in viewDidLoad / setupUI)

What was the problem with using typingAttributes: at some point in time, the memory usage went up and never stopped and caused the app to freeze.

Tung Fam
  • 7,899
  • 4
  • 56
  • 63
7

I ran into the same issue and eventually solved it by setting typingAttributes again after every edit.

Swift 3

func textViewDidChange(_ textView: UITextView) {
    NotesTextView.typingAttributes = [NSForegroundColorAttributeName: UIColor.blue, NSFontAttributeName: UIFont.systemFont(ofSize: 17)]
}
Serdnad
  • 602
  • 2
  • 9
  • 17
1

2023, the only way:

Note that previous solutions such as textViewShouldBeginEditing simply don't work. You must now do these two:

func textViewDidBeginEditing(_ textView: UITextView) {
    _tvHassles()
    outsideDelegate?.textViewDidBeginEditing?(textView)
}

func textViewDidChange(_ textView: UITextView) {
    _tvHassles()
    outsideDelegate?.textViewDidChange?(textView)
}

func _tvHassles() {
    
    let ps = NSMutableParagraphStyle()
    ps.lineSpacing = 3.0 // (means specifically "extra points between lines")
    
    typingAttributes = [
        
        NSAttributedString.Key.foregroundColor: UIColor.green,
        NSAttributedString.Key.font: UIFont. .. your font,
        NSAttributedString.Key.tracking: 0.88,
        NSAttributedString.Key.paragraphStyle: ps
    ]
}

It's utterly absurd that this much needs to be done to set the font in a text entry box, but, there you have it.

Note that of course, it would be insanity in real-life programming to do all this in a view controller. "setting a font" is not vc material, it's view material.

So in practice, do this: https://stackoverflow.com/a/75997746/294884 and put it in your text view class.

Fattie
  • 27,874
  • 70
  • 431
  • 719
0

From iOS 11, Apple clear the attributes after every character.

When the text view’s selection changes, the contents of the dictionary are cleared automatically.

https://developer.apple.com/documentation/uikit/uitextview/1618629-typingattributes

Altimir Antonov
  • 4,966
  • 4
  • 24
  • 26