Skip to content

Instantly share code, notes, and snippets.

@lhoward
Created November 4, 2020 22:21
Show Gist options
  • Select an option

  • Save lhoward/7537977a8073009f7cb1f44173c47994 to your computer and use it in GitHub Desktop.

Select an option

Save lhoward/7537977a8073009f7cb1f44173c47994 to your computer and use it in GitHub Desktop.
import SwiftUI
struct AttributedTextView: TextView, UIViewRepresentable {
let content: NSAttributedString
@Binding var height: CGFloat
var font: UIFont? = nil
var textAlignment: NSTextAlignment = .left
var lineBreakMode: NSLineBreakMode = .byWordWrapping
var textColor: UIColor = UIColor.label
var backgroundColor: UIColor = UIColor.clear
var disableInteraction = false
var disableContextMenuInteraction = false
public func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
textView.isEditable = false
textView.isUserInteractionEnabled = !self.disableInteraction
textView.isScrollEnabled = false
textView.automaticallyAdjustsScrollIndicatorInsets = false
textView.textContainer.lineFragmentPadding = 0
textView.textContainer.lineBreakMode = self.lineBreakMode
textView.contentInset = .zero
textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
textView.font = self.font ?? UIFont.with(font: .body)
textView.adjustsFontForContentSizeCategory = true
textView.textAlignment = self.textAlignment
textView.textColor = self.textColor
textView.backgroundColor = self.backgroundColor
textView.contentSize = .zero
if self.disableContextMenuInteraction,
let contextMenuInteraction = textView.interactions.filter({ $0 is UIContextMenuInteraction }).first as? UIContextMenuInteraction {
textView.removeInteraction(contextMenuInteraction)
}
if let font = self.font {
let content = NSMutableAttributedString(attributedString: self.content)
content.replaceFont(with: font)
textView.attributedText = content
if self.lineBreakMode != .byWordWrapping {
textView.textContainer.maximumNumberOfLines = Int(self.height / font.lineHeight)
}
} else {
textView.attributedText = self.content
}
return textView
}
public func updateUIView(_ textView: UITextView, context: Context) {
DispatchQueue.main.async {
self.height = textView.sizeThatFits(textView.bounds.size).height
}
}
}
extension AttributedTextView {
public func disableInteraction(_ disable: Bool?) -> AttributedTextView {
var view = self
view.disableInteraction = disable ?? false
return view
}
public func disableContextMenuInteraction(_ disable: Bool?) -> AttributedTextView {
var view = self
view.disableContextMenuInteraction = disable ?? false
return view
}
}
private extension NSMutableAttributedString {
func replaceFont(with font: UIFont) {
beginEditing()
self.enumerateAttribute(.font, in: NSRange(location: 0, length: self.length)) { (value, range, stop) in
removeAttribute(.font, range: range)
addAttribute(.font, value: font, range: range)
}
endEditing()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment