Reputation: 1437
Im writing a desktop app in swift for mac 10.11 and I would like to add a link to the about page.
Very much like this: https://developer.apple.com/library/mac/qa/qa1487/_index.html
I haven't been able to find a good tutorial or reference.
Any help would be much appreciated
Upvotes: 8
Views: 5306
Reputation: 1176
swift 4.2
class HyperlinkTextField: NSTextField {
private var detector: NSDataDetector!
override func awakeFromNib() {
super.awakeFromNib()
detector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
}
func setText(text: String ){
let matches = detector.matches(in: text, options: [], range: NSRange(location: 0, length: text.utf16.count))
for match in matches {
guard let range = Range(match.range, in: text) else { continue }
let url = text[range]
let attributedString = NSMutableAttributedString(string: text)
attributedString.addAttribute(.link, value: url, range: match.range)
self.attributedStringValue = attributedString
}
}
}
Upvotes: 0
Reputation: 1437
Swift 4, xCode 9
@IBDesignable
class HyperlinkTextField: NSTextField {
@IBInspectable var href: String = ""
override func resetCursorRects() {
discardCursorRects()
addCursorRect(self.bounds, cursor: NSCursor.pointingHand)
}
override func awakeFromNib() {
super.awakeFromNib()
// TODO: Fix this and get the hover click to work.
let attributes: [NSAttributedStringKey: Any] = [
NSAttributedStringKey.foregroundColor: NSColor.linkColor,
NSAttributedStringKey.underlineStyle: NSUnderlineStyle.styleSingle.rawValue as AnyObject
]
attributedStringValue = NSAttributedString(string: self.stringValue, attributes: attributes)
}
override func mouseDown(with theEvent: NSEvent) {
if let localHref = URL(string: href) {
NSWorkspace.shared.open(localHref)
}
}
}
Upvotes: 7
Reputation: 1198
let link = NSTextField()
link.isBezeled = false
link.drawsBackground = false
link.isEditable = false
link.isSelectable = true
link.allowsEditingTextAttributes = true
let url = URL(string: "http://www.google.com")
let linkTextAttributes: [NSAttributedStringKey: Any] = [
NSAttributedStringKey.underlineStyle: NSUnderlineStyle.styleSingle.rawValue,
NSAttributedStringKey.foregroundColor: NSColor.blue,
NSAttributedStringKey.link: url as Any
]
let string = "whatever"
link.attributedStringValue = NSAttributedString(string: string, attributes: linkTextAttributes)
window.contentView?.addSubview(link)
Upvotes: 1
Reputation: 1046
Modified the existing answers to allow for a substring of the label's text to become underlined and blue, so you can do something like: This is the answer
// A text field that can contain a hyperlink within a range of characters in the text.
@IBDesignable
public class SubstringLinkedTextField: NSTextField {
// the URL that will be opened when the link is clicked.
public var link: String = ""
@available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'link' instead.")
@IBInspectable public var HREF: String {
get {
return self.link
}
set {
self.link = newValue
self.needsDisplay = true
}
}
// the substring within the field's text that will become an underlined link. if empty or no match found, the entire text will become the link.
public var linkText: String = ""
@available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'linkText' instead.")
@IBInspectable public var LinkText: String {
get {
return self.linkText
}
set {
self.linkText = newValue
self.needsDisplay = true
}
}
override public func awakeFromNib() {
super.awakeFromNib()
self.allowsEditingTextAttributes = true
self.isSelectable = true
let url = URL(string: self.link)
let attributes: [NSAttributedStringKey: AnyObject] = [
NSAttributedStringKey(rawValue: NSAttributedStringKey.link.rawValue): url as AnyObject
]
let attributedStr = NSMutableAttributedString(string: self.stringValue)
if self.linkText.count > 0 {
if let range = self.stringValue.indexOf(substring: self.linkText) {
attributedStr.setAttributes(attributes, range: range)
} else {
attributedStr.setAttributes(attributes, range: NSMakeRange(0, self.stringValue.count))
}
} else {
attributedStr.setAttributes(attributes, range: NSMakeRange(0, self.stringValue.count))
}
self.attributedStringValue = attributedStr
}
}
Upvotes: 5
Reputation: 716
Exactly what I needed. Here is the Swift3
version:
import Cocoa
@IBDesignable
class HyperTextField: NSTextField {
@IBInspectable var href: String = ""
override func awakeFromNib() {
super.awakeFromNib()
let attributes: [String: AnyObject] = [
NSForegroundColorAttributeName: NSColor.blue,
NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue as AnyObject
]
self.attributedStringValue = NSAttributedString(string: self.stringValue, attributes: attributes)
}
override func mouseDown(with event: NSEvent) {
NSWorkspace.shared().open(URL(string: self.href)!)
}
}
Upvotes: 3
Reputation: 93161
The easiest way is to subclass NSTextField
to create a HyperlinkTextField
. Below is an example:
First, let's add a HyperlinkTextField
class to your project:
// HyperlinkTextField.swift
import Cocoa
@IBDesignable
class HyperlinkTextField: NSTextField {
@IBInspectable var href: String = ""
override func awakeFromNib() {
super.awakeFromNib()
let attributes: [String: AnyObject] = [
NSForegroundColorAttributeName: NSColor.blueColor(),
NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleSingle.rawValue
]
self.attributedStringValue = NSAttributedString(string: self.stringValue, attributes: attributes)
}
override func mouseDown(theEvent: NSEvent) {
NSWorkspace.sharedWorkspace().openURL(NSURL(string: self.href)!)
}
}
Next, in Interface Builder, drag a label from the Object library to your window.
Select that label, go to the menu View > Utilities > Show Identity Inspector (or press Cmd + Opt + 3
) and change the class to HyperlinkTextField
Go to the Attributes Inspector (Cmd + Opt + 4
) and set Href
to the URL you want to visit.
The label shows black text in Interface Builder but everything will be fine when you run your app. Clicking on the label will open the link in your default browser.
One thing I couldn't achieve was to make the HyperlinkTextField
shows up as blue and underlined in Interface Builder. Comments on how to do that are welcome.
Upvotes: 4