Search code examples
iosuikituitextviewnsattributedstringnstextstorage

UITextView rich text editing


I need to implement a text editor using UITextView that supports:

  • Bold/Italic/Underline
  • Color,Font,font size changes
  • Paragraph alignment
  • List format (bullets, numbers, etc.)
  • Custom selection of text anywhere in the text view and change the properties

So far I have managed to do it without NSTextStorage but it seems I am hitting limits. For instance, to change font, I use UIFontPickerViewController and change the font as follows:

      func fontPickerViewControllerDidPickFont(_ viewController: UIFontPickerViewController) {
         if let selectedFontDesc = viewController.selectedFontDescriptor {
            let font = UIFont(descriptor: selectedFontDesc, size: selectedFontDesc.pointSize)
            self.selectedFont = font
        
            self.textView.typingAttributes = [NSAttributedString.Key.foregroundColor: self.selectedColor ?? UIColor.white, NSAttributedString.Key.font: self.selectedFont ?? UIFont.preferredFont(forTextStyle: .body, compatibleWith: nil)]
        
           if let range = self.textView.selectedTextRange, let selectedFont = selectedFont {
             let attributedText = NSMutableAttributedString(attributedString: self.textView.attributedText)
            
             let location =  textView.offset(from: textView.beginningOfDocument, to: range.start)
             let length = textView.offset(from: range.start, to: range.end)
             let nsRange = NSRange(location: location, length: length)
            
             attributedText.setAttributes([NSAttributedString.Key.font : selectedFont], range: nsRange)
            
             self.textView.attributedText = attributedText
         }
        
     }
 }

This works but the problem is it resets the color of the selected text and other properties. I need to understand a way in which the existing attributed of the text under selection are not disturbed. I suspect the way to do is with using NSTextStorage but I can't find anything good on internet that explains the right use of NSTextStorage to achieve this.


Solution

  • The problem is this call:

    attributedText.setAttributes...
    

    This, as you have observed, makes the attribute you provide (here, the font) the only attribute of this range. Instead, you want to add your font attribute to the existing attributes:

    https://developer.apple.com/documentation/foundation/nsmutableattributedstring/1414304-addattributes