0

I'd like to have the user style a UITextView with multiple styles by selecting the range and the style. To keep it simple right now, I have a UITextView and 2 UIButtons (bold and italic), but I'd love to add multiple styles (colors, size, font weight etc).

var selectedRange: NSRange?
@IBOutlet weak var textBox: UITextView!

let boldAttribute = [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 22, weight: .bold)]
let italicAttribute = [NSAttributedStringKey.font: UIFont.italicSystemFont(ofSize: 15)]

@IBAction func pressedItalic(_ sender: UIButton) {
    if selectedRange != nil {
        let string = NSMutableAttributedString(string: textBox.text)
        string.addAttributes(italicAttribute, range: selectedRange!)
        textBox.attributedText = string
    }
}


@IBAction func pressedBold(_ sender: UIButton) {
    if selectedRange != nil {
        let string = NSMutableAttributedString(string: textBox.text)
        string.addAttributes(boldAttribute, range: selectedRange!)
        textBox.attributedText = string
    }
}


override func viewDidLoad() {
    super.viewDidLoad()
    textBox.delegate = self
}


func textViewDidChangeSelection(_ textView: UITextView) {
    selectedRange = textView.selectedRange
    print(selectedRange)

}

The problem: when selecting a new style, the previous selection and selected style goes back to the default. How can I add multiple different styles to one text view without refreshing it every time? My end goal is to build something similar to the prebuilt iOS notes app, where the user can fully customize the styles and layout of the text.

UPDATE:

I'd like the show the controls (buttons) to the user at all time. Is that also possible with a UIMenuController?

EDIT:

I'd love to be able to control all styles (color, font weight, size etc)

Thanks!!!

robinyapockets
  • 363
  • 5
  • 21
  • You don't need any of this. Simple set the `allowsEditingTextAttributes` property of the `UITextView` to `true`. – rmaddy Jul 19 '18 at 16:07
  • Thanks @rmaddy but I'd like to customize the UI and show these actions to the user in ways beyond the UIMenuController. For example I like how the controls are visible to the user in the Note app above the keyboard at all time. Is that also possible with UIMenuController? Thanks! – robinyapockets Jul 19 '18 at 16:26

2 Answers2

1

Rather than mutating the string yourself you can use the methods in the UIResponderStandardEditActions protocol. This protocol is already attached to UITextView and provides access to all the text editing functions available to the user, including toggleBoldFace() and toggleItalics(). These allow multiple different styles to manipulate the text. You can just call them on the textview:

@IBAction func pressedBold(_ sender: UIButton) {
    textBox.toggleBoldface(self)
}

See: Apple's Developer Documentation on UIResponderStandardEditActions

teacup
  • 624
  • 1
  • 8
  • 18
  • 1
    Thanks! It does answer my question to bold and italic perfectly. How would you suggest I add multiple text styles, like color, size or font changes? – robinyapockets Jul 20 '18 at 07:20
0

I ended up solving it be declaring the NSMutableAttributedString at ViewDidLoad

var string: NSMutableAttributedString?

override func viewDidLoad() {
    super.viewDidLoad()
    string = NSMutableAttributedString(string: textBox.text)
}

And then using the beginEditing() and endEditing() methods on that string with each action.

@IBAction func pressedItalic(_ sender: UIButton) {
    if selectedRange != nil {
        string?.beginEditing()
        string?.addAttributes(italicAttribute, range: selectedRange!)
        textBox.attributedText = string
        string?.endEditing()
    }
}

This way I can add endless style attributes (size, color, weight etc) to the string sequentially.

robinyapockets
  • 363
  • 5
  • 21