Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple clickable link in Cocoa and Swift

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

like image 407
jeremyforan Avatar asked Jul 12 '16 23:07

jeremyforan


People also ask

How do I make a link clickable in Swift?

Use NSMutableAttributedString. NSMutableAttributedString * str = [[NSMutableAttributedString alloc] initWithString:@"Google"]; [str addAttribute: NSLinkAttributeName value: @"http://www.google.com" range: NSMakeRange(0, str. length)]; yourTextView.

How do you make text clickable in Swift?

To make UILabel clickable you will need to enable user interaction for it. To enable user interaction for UILabel simply set the isUserInteractionEnabled property to true.

How do I add a link in UILabel?

Key value named hyperlink and adding text attributes when the attribute is present. Let's now create a convenience method which creates NSAttributedString and sets it to the HyperlinkLabel. let attributedString = NSMutableAttributedString(string: "Check this webpage: %0$@. Link to %1$@ on the App Store.


3 Answers

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)
        }
    }
}
like image 187
jeremyforan Avatar answered Oct 16 '22 06:10

jeremyforan


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
    }
}
like image 33
GabeV Avatar answered Oct 16 '22 05:10

GabeV


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

Identity Inspector

Go to the Attributes Inspector (Cmd + Opt + 4) and set Href to the URL you want to visit.

Attributes Inspector

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.

like image 4
Code Different Avatar answered Oct 16 '22 05:10

Code Different