Skip to content

Instantly share code, notes, and snippets.

@drewdeponte
Created February 19, 2021 03:56
Show Gist options
  • Save drewdeponte/055499cb1b88abdbc27e73f14a1c4de3 to your computer and use it in GitHub Desktop.
Save drewdeponte/055499cb1b88abdbc27e73f14a1c4de3 to your computer and use it in GitHub Desktop.
SwiftUI TextWithAttributedString
public struct TextWithAttributedString: NSViewRepresentable {
public typealias NSViewType = NSTextField
public class Coordinator: NSObject, NSGestureRecognizerDelegate {
let doubleTapCallback: () -> ()
public init(doubleTapCallback: @escaping () -> ()) {
self.doubleTapCallback = doubleTapCallback
}
@objc func doubleTapped(sender:NSClickGestureRecognizer) {
self.doubleTapCallback()
}
}
let attributedString: NSAttributedString
let maximumNumberOfLines: Int
let doubleTapCallback: () -> ()
public init(attributedString: NSAttributedString, lineLimit: Int = 0, doubleTapCallback: @escaping () -> () = { }) {
self.attributedString = attributedString
self.maximumNumberOfLines = lineLimit
self.doubleTapCallback = doubleTapCallback
}
public func makeCoordinator() -> TextWithAttributedString.Coordinator {
print("DREW: about to construct coordinator in makeCoordinator.")
return Coordinator(doubleTapCallback: self.doubleTapCallback)
}
public func makeNSView(context: Context) -> NSTextField {
let tf = NSTextField(labelWithString: "")
tf.maximumNumberOfLines = self.maximumNumberOfLines
tf.alignment = .left
tf.lineBreakMode = .byWordWrapping
tf.autoresizesSubviews = true
tf.drawsBackground = true
tf.backgroundColor = NSColor.purple
tf.setContentCompressionResistancePriority(NSLayoutConstraint.Priority(250), for: .horizontal)
tf.cell?.truncatesLastVisibleLine = true // add the elipse on the last line that is truncated
tf.autoresizingMask = [NSView.AutoresizingMask.width, NSView.AutoresizingMask.height]
let tapGestureRecognizer = NSClickGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.doubleTapped(sender:)))
tapGestureRecognizer.numberOfClicksRequired = 2
tapGestureRecognizer.delegate = context.coordinator
tf.addGestureRecognizer(tapGestureRecognizer)
return tf
}
public func updateNSView(_ nsView: NSTextField, context: Context) {
nsView.attributedStringValue = attributedString
}
public func foregroundColor(_ color: NSColor) -> TextWithAttributedString {
let mutableAttributedString = NSMutableAttributedString(attributedString: self.attributedString)
let completeRange = NSRange(location: 0, length: mutableAttributedString.length)
mutableAttributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: color, range: completeRange)
// NOTE: I have to do this because it turns out the Markdown library Down is introducing whitespace/newlines at the end of the content which is making it appear weird.
return TextWithAttributedString(attributedString: mutableAttributedString.attributedStringByTrimmingCharacterSet(charSet: .whitespacesAndNewlines))
}
public func lineLimit(_ number: Int) -> TextWithAttributedString {
return TextWithAttributedString(attributedString: self.attributedString, lineLimit: number)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment