0

I have a chat app with the UITextView with a dynamic text (comes from the server or is typed by the user). I needed to detect all types of links, and the UITextView does a great job in detecting phone numbers, addresses, hyperlinks and calendar events. Where UITextView falls short is styling, there are multiple problems there:

  1. The address links are not colored with the tintColor or with the color from linkTextAttributes property, or using the appearance() proxy.
  2. All of the links are underlined by default.
  3. Some of the links are colored properly, but I fail to see a pattern why certain links are omitted (looks like it may have something to do with the word wrap).
  4. When setting custom underlineStyle attribute, the text simply disappears.

So I thought the best thing to do would be to still use the UITextView for detecting the links, but then create my own attributed string and style everything the way I want. For this I need the ranges for the links, but I can't find the way to get them.

I tried this:

open func enumerateAttributes(in enumerationRange: NSRange, options opts: NSAttributedString.EnumerationOptions = [], using block: ([NSAttributedString.Key : Any], NSRange, UnsafeMutablePointer<ObjCBool>) -> Void)

But there are never any .link elements, nor any underline attributes if I look for them. So the question is, is there a way to get the link ranges from the UITextView somehow? Or perhaps there is a way to reliably style the links that I'm missing?

lawicko
  • 7,246
  • 3
  • 37
  • 49
  • Phone Numbers, addresses etc, there are detected using the Data Detector mechanism. See there https://stackoverflow.com/questions/41077174/extracting-address-elements-from-a-string-using-nsdatadetector-in-swift-3-0 to enumerate I think you'll be able to work with the `match.range` then ;) – Larme Dec 11 '20 at 10:06
  • @Larme awesome, this will allow me to forget the UITextView all together and style everything myself. If you write this in an answer I will accept it. – lawicko Dec 11 '20 at 11:14

1 Answers1

1

To detect the Phone Numbers, addresses etc, you are in fact using the NSDataDetector.

That's what you in fact set in InterfaceBuilder there:

enter image description here

Then:

let types: NSTextCheckingResult.CheckingType = [.address, .link, .phoneNumber, .date]
let detector = try? NSDataDetector(types: types.rawValue)
let matches = detector.matches(in: text, options: [], range: NSRange(location: 0, length: text.utf16.count))
matches.forEach {
    guard let range = Range($0.range, in: text) else { return }
    let sub = String(text[range])
    print(sub)
}
Larme
  • 24,190
  • 6
  • 51
  • 81
  • Do we need the Authorization for Calendar or Reminder App? if the iOS shows the action controller on tapping detected links? This is the default behavior. I am not using any API to create events or reminders. – K_Mohit Apr 19 '21 at 14:48