Skip to content

Instantly share code, notes, and snippets.

@banjun
Last active May 2, 2024 07:53
Show Gist options
  • Save banjun/b6ea9f025a290af4186da6875b55295e to your computer and use it in GitHub Desktop.
Save banjun/b6ea9f025a290af4186da6875b55295e to your computer and use it in GitHub Desktop.
SwiftUI multi column text backed by TextKit 1 multi column layout
struct MultiColumnText: View {
private let storage: NSTextStorage
private let layoutManager: NSLayoutManager = .init()
private let containers: [NSTextContainer]
init(text: NSAttributedString, columns: Int) {
storage = .init(attributedString: text)
storage.addLayoutManager(layoutManager)
containers = (0..<columns).map {_ in .init()}
containers.forEach {
$0.widthTracksTextView = true
$0.heightTracksTextView = true
layoutManager.addTextContainer($0)
}
}
var body: some View {
HStack(alignment: .top) {
ForEach(containers, id: \.self) {
TextView(container: $0)
}
}
}
struct TextView: UIViewRepresentable {
let container: NSTextContainer
func makeUIView(context: Context) -> UIView {
let v = UIView()
let tv = UITextView(frame: .zero, textContainer: container)
tv.isScrollEnabled = false
tv.isEditable = false
tv.translatesAutoresizingMaskIntoConstraints = false
v.addSubview(tv)
tv.leadingAnchor.constraint(equalTo: v.leadingAnchor).isActive = true
tv.trailingAnchor.constraint(equalTo: v.trailingAnchor).isActive = true
tv.topAnchor.constraint(equalTo: v.topAnchor).isActive = true
tv.bottomAnchor.constraint(equalTo: v.bottomAnchor).isActive = true
return v
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}
}