Skip to content

Instantly share code, notes, and snippets.

@kylehowells
Created March 20, 2024 01:24
Show Gist options
  • Save kylehowells/d3a9b2f2897bd58e42a3eb801456188a to your computer and use it in GitHub Desktop.
Save kylehowells/d3a9b2f2897bd58e42a3eb801456188a to your computer and use it in GitHub Desktop.

Revisions

  1. kylehowells created this gist Mar 20, 2024.
    118 changes: 118 additions & 0 deletions Tap links in UILabel.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,118 @@
    // Setup Label

    let label: UILabel = {
    let label = UILabel()
    label.isUserInteractionEnabled = true

    label.adjustsFontSizeToFitWidth = true
    label.numberOfLines = 0

    label.textColor = UIColor(white: 0, alpha: 1)
    label.tintColor = UIColor.red

    label.textAlignment = .center

    let fontSize: CGFloat = 20

    label.font = UIFont.systemFont(ofSize: fontSize, weight: .medium)

    // - Attributes

    let attributes: [NSAttributedString.Key : Any] = [
    .font : UIFont.systemFont(ofSize: fontSize, weight: .regular),
    .foregroundColor: UIColor(white: 0, alpha: 0.6)
    ]

    let linkAttributes: [NSAttributedString.Key : Any] = [
    .font : UIFont.systemFont(ofSize: fontSize, weight: .medium),
    .foregroundColor: UIColor(white: 0, alpha: 1),
    .attachment: "https://google.com"
    ]

    let attributedString: NSMutableAttributedString = NSMutableAttributedString(string: "", attributes: attributes)

    attributedString.append(NSAttributedString(
    string: "Hello",
    attributes: attributes
    ))

    attributedString.append(NSAttributedString(
    string: " World ",
    attributes: linkAttributes
    ))

    attributedString.append(NSAttributedString(
    string: "Testing",
    attributes: attributes
    ))

    label.attributedText = attributedString

    label.layer.borderWidth = 1
    label.layer.borderColor = UIColor(white: 0, alpha: 1).cgColor

    return label
    }()


    // MARK: - Tap Label

    @objc func tappedOnLabel(tapGesture: UITapGestureRecognizer) {
    guard tapGesture.state == .recognized else { return }
    print("tapGesture.state: \(tapGesture.state)")

    let locationOfTouchInLabel: CGPoint = tapGesture.location(in: self._view.label)

    print("self.tapLabel( locationOfTouchInLabel: \(locationOfTouchInLabel) )")

    let label: UILabel = self._view.label

    let attributedText: NSAttributedString = label.attributedText!

    // Create instances of NSLayoutManager, NSTextContainer and NSTextStorage
    let layoutManager: NSLayoutManager = NSLayoutManager()
    let textContainer: NSTextContainer = NSTextContainer(size: CGSize.zero)
    let textStorage: NSTextStorage = NSTextStorage(attributedString: attributedText)

    // Configure layoutManager and textStorage
    layoutManager.addTextContainer(textContainer)
    textStorage.addLayoutManager(layoutManager)

    // Configure textContainer
    textContainer.lineFragmentPadding = 0.0
    textContainer.lineBreakMode = label.lineBreakMode
    textContainer.maximumNumberOfLines = label.numberOfLines

    let labelSize: CGSize = label.bounds.size
    textContainer.size = labelSize

    let textBoundingBox: CGRect = layoutManager.usedRect(for: textContainer)

    // - NSTextStorage

    let textContainerOffset: CGPoint = CGPoint(
    x: (labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
    y: (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y
    )

    let locationOfTouchInTextContainer: CGPoint = CGPoint(
    x: locationOfTouchInLabel.x - textContainerOffset.x,
    y: locationOfTouchInLabel.y - textContainerOffset.y
    )

    let indexOfCharacter: Int = layoutManager.characterIndex(
    for: locationOfTouchInTextContainer,
    in: textContainer,
    fractionOfDistanceBetweenInsertionPoints: nil
    )

    let attachment = attributedText.attribute(.attachment, at: indexOfCharacter, effectiveRange: nil)

    print("attachment: \(attachment) - \( type(of: attachment) )")

    if let textLink: String = attachment as? String,
    let url: URL = URL(string: textLink)
    {
    UIApplication.shared.open(url)
    }
    }