61

I have a UITextView object. The text in UIView has a phone number, mail link, a website link. I want to show them as links with following functionality.

When someone taps on URL - Safari should open the the website. When someone taps on email link - Mail should open up with my address in to field When someone taps on phone number - Phone application should call the number

Has anyone done this before or knows how to handle it?

Thanks, AJ

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
AJ.
  • 1,443
  • 7
  • 19
  • 31

8 Answers8

110

If you are using OS3.0

you can do it like the following

textview.editable = NO;
textview.dataDetectorTypes = UIDataDetectorTypeAll;
18

A note on detecting email addresses: The Mail app must be installed (it's not on the iOS Simulator) for email links to open a message compose screen.

Andrew Hershberger
  • 4,152
  • 1
  • 25
  • 35
17

Swift 3.0 +

As of swift 3.0, use the following code if you want to do it programmatically.

textview.isEditable = false
textview.dataDetectorTypes = .all

Or if you have a storyboard

enter image description here

Community
  • 1
  • 1
Fangming
  • 24,551
  • 6
  • 100
  • 90
8

Though the Question is super Old. Still if anyone faces the same issue,

Also it can be used as a UILabel. Though Below solution will do the job : [There isn't a need for any library..]

So I've used MFMailcomposer() and UITexView [ Code is in Swift 3.0 - Xcode 8.3.2 ]

A 100% Crash Proof and Working Code Handles all the corner cases. =D

Step 1.

import MessageUI

Step 2. Add the delegate

class ViewController: UITextViewDelegate, MFMailComposeViewControllerDelegate{

Step 3. Add the textView IBOutlet From StoryBoard

@IBOutlet weak var infoTextView: UITextView!

Step 4. Call the below method in your viewDidload()

func addInfoToTextView()  {
    let attributedString = NSMutableAttributedString(string: "For further info call us on : \(phoneNumber)\nor mail us at : \(email)")
    attributedString.addAttribute(NSLinkAttributeName, value: "tel://", range: NSRange(location: 30, length: 10))
    attributedString.addAttribute(NSLinkAttributeName, value: "mailto:", range: NSRange(location: 57, length: 18))
    self.infoTextView.attributedText = attributedString
    self.infoTextView.linkTextAttributes = [NSForegroundColorAttributeName:UIColor.blue, NSUnderlineStyleAttributeName:NSNumber(value: 0)]
    self.infoTextView.textColor = .white
    self.infoTextView.textAlignment = .center
    self.infoTextView.isEditable = false
    self.infoTextView.dataDetectorTypes = UIDataDetectorTypes.all
    self.infoTextView.delegate = self
}

Step 5. Implement delegate methods for TextView

@available(iOS, deprecated: 10.0)
func textView(_ textView: UITextView, shouldInteractWith url: URL, in characterRange: NSRange) -> Bool {
    if (url.scheme?.contains("mailto"))! && characterRange.location > 55{
        openMFMail()
    }
    if (url.scheme?.contains("tel"))! && (characterRange.location > 29 && characterRange.location < 39){
        callNumber()
    }
    return false
}

//For iOS 10
@available(iOS 10.0, *)
func textView(_ textView: UITextView, shouldInteractWith url: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
    if (url.scheme?.contains("mailto"))! && characterRange.location > 55{
        openMFMail()
    }
    if (url.scheme?.contains("tel"))! && (characterRange.location > 29 && characterRange.location < 39){
        callNumber()
    }
    return false
}

Step 6. Write the helper Methods to open MailComposer and Call App

func callNumber() {
    if let phoneCallURL = URL(string: "tel://\(phoneNumber)")
    {
        let application:UIApplication = UIApplication.shared
        if (application.canOpenURL(phoneCallURL))
        {
            let alert = UIAlertController(title: "Call", message: "\(phoneNumber)", preferredStyle: UIAlertControllerStyle.alert)
            if #available(iOS 10.0, *)
            {
                alert.addAction(UIAlertAction(title: "Call", style: .cancel, handler: { (UIAlertAction) in
                    application.open(phoneCallURL, options: [:], completionHandler: nil)
                }))
            }
            else
            {
                alert.addAction(UIAlertAction(title: "Call", style: .cancel, handler: { (UIAlertAction) in
                    application.openURL(phoneCallURL)
                }))
            }

            alert.addAction(UIAlertAction(title: "cancel", style: .default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        }
    }
    else
    {
        self.showAlert("Couldn't", message: "Call, cannot open Phone Screen")
    }
}
func openMFMail(){
    let mailComposer = MFMailComposeViewController()
    mailComposer.mailComposeDelegate = self
    mailComposer.setToRecipients(["\(email)"])
    mailComposer.setSubject("Subject..")
    mailComposer.setMessageBody("Please share your problem.", isHTML: false)
    present(mailComposer, animated: true, completion: nil)

}

Step 7. Write MFMailComposer's Delegate Method

func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
    switch result {
    case .cancelled:
        print("Mail cancelled")
    case .saved:
        print("Mail saved")
    case .sent:
        print("Mail sent")
    case .failed:
        print("Mail sent failure: \(String(describing: error?.localizedDescription))")
    default:
        break
    }
    controller.dismiss(animated: true, completion: nil)
}

That's it you're Done... =D

Here is the swift file for the above code : textViewWithEmailAndPhone.swift

Set the below properties to Use it as a UILabel

Here's the image for that..

Yash Bedi
  • 1,323
  • 17
  • 25
1

Step 1. Create a subclass of UITextview and override the canBecomeFirstResponder function

KDTextView.h Code:

@interface KDTextView : UITextView

@end

KDTextView.m Code:

#import "KDTextView.h"

// Textview to disable the selection options

@implementation KDTextView

- (BOOL)canBecomeFirstResponder {
    return NO;
}

@end

Step 2. Create the Textview using subclass KDTextView

KDTextView*_textView = [[KDTextView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    [_textView setScrollEnabled:false];
    [_textView setEditable:false];
    _textView.delegate = self;
    [_textView setDataDetectorTypes:UIDataDetectorTypeAll];
    _textView.selectable = YES;
    _textView.delaysContentTouches = NO;
    _textView.userInteractionEnabled = YES;
    [self.view addSubview:_textView];

Step 3: Implement the delegate method

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
{
    return true;
}
Kuldeep Singh
  • 336
  • 3
  • 12
  • Got some idea from your answer. My problem solved with subclassing UITextView and overriding var canBecomeFirstResponder: Bool { return false }. Thank you for your answer.@kuldeep-singh – Syed Sadrul Ullah Sahad Feb 19 '20 at 05:22
1

If you want to auto detect links, email etc Please make sure "isSelectable" is set to true.

textview.isSelectable = true
textview.editable = false
textview.dataDetectorTypes = .all
aqsa arshad
  • 801
  • 8
  • 27
0

Swift 4.2 Xcode 10.1

func setupContactUsTextView() {
        let text = NSMutableAttributedString(string: "Love your App, but need more help? Text, Call (123) 456-1234 or email ")
        if let font = UIFont(name: "Calibri", size: 17) {
            text.addAttribute(NSAttributedStringKey.font,
                              value: font,
                              range: NSRange(location: 0, length: text.length))
        } else {
            text.addAttribute(NSAttributedStringKey.font,
                              value: UIFont.systemFont(ofSize: 17),
                              range: NSRange(location: 0, length: text.length))
        }
        text.addAttribute(NSAttributedStringKey.foregroundColor,
                          value: UIColor.init(red: 112/255, green: 112/255, blue: 112/255, alpha: 1.0),
                          range: NSRange(location: 0, length: text.length))
        text.addAttribute(NSAttributedStringKey.link, value: "tel://", range: NSRange(location: 49, length: 15))
        let interactableText = NSMutableAttributedString(string: "contact@abc.com")
        if let font = UIFont(name: "Calibri", size: 17) {
            interactableText.addAttribute(NSAttributedStringKey.font,
                                          value: font,
                                          range: NSRange(location: 0, length: interactableText.length))
        } else {
            interactableText.addAttribute(NSAttributedStringKey.font,
                                          value: UIFont.systemFont(ofSize: 17),
                                          range: NSRange(location: 0, length: interactableText.length))
        }
        interactableText.addAttribute(NSAttributedStringKey.link,
                                      value: "contact@abc.com",
                                      range: NSRange(location: 0, length: interactableText.length))
        interactableText.addAttribute(NSAttributedStringKey.underlineStyle,
                                      value: NSUnderlineStyle.styleSingle.rawValue,
                                      range: NSRange(location: 0, length: interactableText.length))
        text.append(interactableText)
        videoDescTextView.attributedText = text
        videoDescTextView.textAlignment = .center
        videoDescTextView.isEditable = false
        videoDescTextView.isSelectable = true
        videoDescTextView.delegate = self
    }

    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
        if (characterRange.location > 48 && characterRange.location < 65){
            print("open phone")
        }else{
            print("open gmail")
        }
        return false
    }

Steps - 1. Set the delegate to your text field and don't forget to implement UITextViewDelegate 2. Take the textView outlet - @IBOutlet weak var videoDescTextView: UITextView! 3. Add these two functions given above. This function shows how to detect phone numbers, email from textView, how to underline your email id, how to give custom color to your text, custom font, how to call a function when tapping on phone or email, etc.

Hope this will help someone to save their valuable time. Happy Coding :)

Prashant Gaikwad
  • 3,493
  • 1
  • 24
  • 26
0

I'm curious, do you have control over the text shown? If so, you should probably just stick it in a UIWebView and throw some links in there to do it "the right way".

Ed Marty
  • 39,590
  • 19
  • 103
  • 156
  • 1
    There is a property (in SDK 3.0) dataDetectorTypes for UITextView. Which does the job of detecting links in text. But I am kinda unable to figure out how to use it. For versions prior to 3.0 I have used UIButton and make them look like links. On there touch event I am calling a method which has an NSURL object to the website. Using mailto: would open the email in Mail app. Using Tel: would call the number. But thats the work around. Even after spendin 2 hours, still not able to figure out how to make UITextView handle these guys. – AJ. Jun 15 '09 at 16:41