Skip to content

Instantly share code, notes, and snippets.

@cjnevin
Created November 21, 2019 23:44
Show Gist options
  • Save cjnevin/418b87124499a0221b072b5db1b45f95 to your computer and use it in GitHub Desktop.
Save cjnevin/418b87124499a0221b072b5db1b45f95 to your computer and use it in GitHub Desktop.
import SwiftUI
struct WrappingStack<T: View>: UIViewRepresentable {
@Binding var views: [T]
let spacing: CGFloat
func makeUIView(context: Context) -> WrappingStackView {
let view = WrappingStackView()
view.spacing = spacing
return view
}
func updateUIView(_ uiView: WrappingStackView, context: Context) {
uiView.views = views.map { UIHostingController(rootView: $0).view }
}
}
class WrappingStackView: UIStackView {
var views: [UIView] = [] {
didSet {
render()
}
}
override func layoutSubviews() {
super.layoutSubviews()
render()
}
private func removeAllArrangedSubviews() {
arrangedSubviews.forEach {
self.removeArrangedSubview($0)
$0.removeFromSuperview()
}
}
private func addRow() -> UIView {
let view: UIView = UIView()
addArrangedSubview(view)
return view
}
private func render() {
axis = .vertical
removeAllArrangedSubviews()
var row = addRow()
var currentY: CGFloat = 0
var copy = views
while !copy.isEmpty {
let column = copy.removeFirst()
var currentX = row.subviews.reduce(CGFloat(row.subviews.count) * spacing) { current, view in
current + view.intrinsicContentSize.width
}
if currentX + spacing + column.intrinsicContentSize.width > frame.width {
currentX = 0
currentY += column.intrinsicContentSize.height + spacing
row = addRow()
}
row.addSubview(column)
column.frame = CGRect(origin: .init(x: currentX, y: currentY), size: column.intrinsicContentSize)
}
}
}
struct TagView: View {
let text: String
var body: some View {
Text(text)
.lineLimit(1)
.padding(10)
.background(Color.blue)
.foregroundColor(Color.white)
.cornerRadius(15)
}
}
struct TagCloudView: View {
@Binding var texts: [String]
var body: some View {
WrappingStack(views: .constant(texts.map(TagView.init)), spacing: 5)
}
}
struct TagCloudView_Previews: PreviewProvider {
static var previews: some View {
TagCloudView(texts: .constant([
"alcohol", "stress", "binge", "lazy", "running", "car", "cycling", "boating", "mountain biking", "bus", "spelunking"
])).padding(10)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment