Reputation: 167
Suppose I have an AttributedString: "Already have an account? Sign in!".
I am placing this String in UILabel. Now when a user clicks on "Sign in!", the current viewController should go to another viewController or some function should be called while clicking on sign in.
Any code or suggestion should be fine.
Upvotes: 11
Views: 40276
Reputation: 37290
There's no need to use a separate gesture recognizer as some of the answers state. Instead, you can use attributed text in combination with the UITextViewDelegate
's textView:shouldInteractWithURL:inRange:interaction:
method to achieve this, ex:
class ViewController: UIViewController, UITextViewDelegate {
@IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let text = NSMutableAttributedString(string: "Already have an account? ")
text.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: 12), range: NSMakeRange(0, text.length))
let selectablePart = NSMutableAttributedString(string: "Sign in!")
selectablePart.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: 12), range: NSMakeRange(0, selectablePart.length))
// Add an underline to indicate this portion of text is selectable (optional)
selectablePart.addAttribute(NSAttributedString.Key.underlineStyle, value: 1, range: NSMakeRange(0,selectablePart.length))
selectablePart.addAttribute(NSAttributedString.Key.underlineColor, value: UIColor.black, range: NSMakeRange(0, selectablePart.length))
// Add an NSLinkAttributeName with a value of an url or anything else
selectablePart.addAttribute(NSAttributedString.Key.link, value: "signin", range: NSMakeRange(0,selectablePart.length))
// Combine the non-selectable string with the selectable string
text.append(selectablePart)
// Center the text (optional)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = NSTextAlignment.center
text.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, text.length))
// To set the link text color (optional)
textView.linkTextAttributes = [NSAttributedString.Key.foregroundColor:UIColor.black, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12)]
// Set the text view to contain the attributed text
textView.attributedText = text
// Disable editing, but enable selectable so that the link can be selected
textView.isEditable = false
textView.isSelectable = true
// Set the delegate in order to use textView(_:shouldInteractWithURL:inRange)
textView.delegate = self
}
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
// **Perform sign in action here**
return false
}
}
Upvotes: 22
Reputation: 3802
Swift 4.2 and Xcode 11
Using a TextView it's much easier:
func setupContactUsInTextView() {
let text = NSMutableAttributedString(string: "Contact us at email ")
text.addAttribute(NSAttributedStringKey.font,
value: UIFont.systemFont(ofSize: 17),
range: NSRange(location: 0, length: text.length))
let interactableText = NSMutableAttributedString(string: "[email protected]")
interactableText.addAttribute(NSAttributedStringKey.font,
value: UIFont.systemFont(ofSize: 17),
range: NSRange(location: 0, length: interactableText.length))
interactableText.addAttribute(NSAttributedStringKey.link,
value: "[email protected]",
range: NSRange(location: 0, length: interactableText.length))
text.append(interactableText)
contactUsTextView.attributedText = text
contactUsTextView.textAlignment = .center
contactUsTextView.isEditable = false
contactUsTextView.isSelectable = true
contactUsTextView.delegate = self
}
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
print("open website here...")
return false
}
Upvotes: 1
Reputation: 2859
Instead of Label you can use a textview to open a View Controller or make substring clickable.
Create an attribute for the string which you want to make clickable
let linkAttributes = [
NSLinkAttributeName: NSURL(string: "https://www.apple.com")!,
NSForegroundColorAttributeName: UIColor.blue
] as [String : Any]
Make your string an attributed string
let attributedString = NSMutableAttributedString(string:"My name is Jarvis")
attributedString.setAttributes(linkAttributes, range: NSMakeRange(5, 10))
You can give your custom range here.
Add an attributed text to your textview
YourTextView.attributedText = attributedString
Then implement the following delegate method of textview to implement interaction for a URL
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
// Here write your code of navigation
return false
}
If you want to do it with label, click see How can I make a clickable link in an NSAttributedString?.
Upvotes: 4
Reputation: 131418
You can add a tap gesture recognizer to your label/view, or you can embed a link with a custom URL protocol into your attributed string, use a UITextView, and turn on link detection. You would then need to implement the UITextView delegate method for responding to links.
I have a demo project called DatesInSwift (link) on GitHub that implements clickable links in a UITextView. Take a look at the UITextView
delegate method textView(_:shouldInteractWithURL:inRange)
in ViewController.swift
. That's the method that tells the text view that it should respond to the URL.
Then you have to implement a UIApplicationDelegate method to handle the URL. The sample app uses application(_:openURL:sourceApplication:annotation)
, which was deprecated in iOS 9. For new development you should use application(_:openURL:options:)
instead.
You will also need to add a CFBundleURLTypes
/ CFBundleURLSchemes
entry to your info.plist to register a custom URL scheme (like myompany.myapp.loginURL
) in order for clicking on an embedded URL to invoke your app.
Upvotes: 2
Reputation: 697
You need to use UITextView:
class ViewController: UIViewController, UIGestureRecognizerDelegate {
@IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let attribute:NSAttributedString = NSAttributedString(string: "Already have an account? Sign in!", attributes: ["Tag" : true])
textView.attributedText = attribute
let tap = UITapGestureRecognizer(target: self, action: #selector(self.textTapped(_:)))
tap.delegate = self
textView.userInteractionEnabled = true
textView.addGestureRecognizer(tap)
}
func textTapped(recognizer:UITapGestureRecognizer) {
let textView:UITextView = recognizer.view as! UITextView
// Location of the tap in text-container coordinates
let layoutManager = textView.layoutManager
var location:CGPoint = recognizer.locationInView(textView)
location.x -= textView.textContainerInset.left
location.y -= textView.textContainerInset.top
var distance:CGFloat?
// Find the character that's been tapped on
let characterIndex = layoutManager.characterIndexForPoint(location, inTextContainer: textView.textContainer, fractionOfDistanceBetweenInsertionPoints: &distance!)
if characterIndex < textView.textStorage.length{
var range:NSRange?
let value = textView.attributedText.attribute("Tag", atIndex: characterIndex, effectiveRange: &range!)
if value {
// add your code here
}
}
}
}
Upvotes: -2
Reputation: 2273
Language update based on @Lindsey Scott answer :)
class ViewController: UIViewController, UITextViewDelegate {
@IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let text = NSMutableAttributedString(string: "Already have an account? ")
text.addAttribute(NSAttributedStringKey.font,
value: UIFont.systemFont(ofSize: 12),
range: NSRange(location: 0, length: text.length))
let interactableText = NSMutableAttributedString(string: "Sign in!")
interactableText.addAttribute(NSAttributedStringKey.font,
value: UIFont.systemFont(ofSize: 12),
range: NSRange(location: 0, length: interactableText.length))
// Adding the link interaction to the interactable text
interactableText.addAttribute(NSAttributedStringKey.link,
value: "SignInPseudoLink",
range: NSRange(location: 0, length: interactableText.length))
// Adding it all together
text.append(interactableText)
// Set the text view to contain the attributed text
textView.attributedText = text
// Disable editing, but enable selectable so that the link can be selected
textView.isEditable = false
textView.isSelectable = true
textView.delegate = self
}
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
//Code to the respective action
return false
}
}
Upvotes: 4
Reputation: 2693
You can apply tapGesture to the label.
Create tap gesture recognizer:
let tapGesture = UITapGestureRecognizer(target: self, action: "YOUR_METHOD:")
Add gesture recognizer to label:
YOUR_LABEL.addGestureRecognizer(tapGesture)
Perform your tasks in this method:
func YOUR_METHOD(sender:UITapGestureRecognizer){
// Perform your operations here.
}
Upvotes: -9