Preventing the labels to be cutting off from the sides - TagsView

Viewed 96

I am building a TagsView in SwiftUI, which can display words as tags. The basic implementation works but it cuts off the labels from the side. I am sure there is something wrong with my algorithm. Here is the screenshot:

enter image description here

And here is the complete code to create the TagsView. The code also includes test data.

struct TagsView: View {
    
    let items: [String]
    let screenWidth = UIScreen.main.bounds.width
    var groupedItems: [[String]] = [[String]]()
    var backgroundColor: Color
    var foregroundColor: Color
    
    init(items: [String], backgroundColor: Color = Color.blue, foregroundColor: Color = Color.white) {
        
        self.items = ["iusto", "assumenda", "hic", "omnis", "labore", "dolorem", "aut", "aliquam", "voluptatibus", "et", "placeat", "soluta", "qui", "voluptatibus", "possimus", "velit", "eaque", "commodi", "dolor", "dicta", "cum", "aperiam", "hic", "maxime", "mollitia", "itaque", "molestiae", "nemo", "eligendi", "unde", "tempore", "sit", "velit", "qui", "ut", "praesentium", "fugit", "velit", "error", "aut", "nulla", "est", "est", "similique", "aut", "laborum", "dolorem", "voluptatem", "nobis", "quaerat"]
        self.backgroundColor = backgroundColor
        self.foregroundColor = foregroundColor
        groupedItems = createGroupedItems(items)
    }
    
    private func createGroupedItems(_ items: [String]) -> [[String]] {
        
        var groupedItems: [[String]] = [[String]]()
        var tempItems: [String] =  [String]()
        
        var width: CGFloat = 0
        
        for word in items {
            
            let label = UILabel()
            label.text = word
            
            label.sizeToFit()
            let viewWidth = label.frame.size.width
            
            print("viewWidth = \(viewWidth)")
            if (width + viewWidth) < screenWidth {
                width += viewWidth
                print("width = \(width)")
                tempItems.append(word)
            } else {
                print("ELSE")
                width = viewWidth
                groupedItems.append(tempItems)
                tempItems.removeAll()
                tempItems.append(word)
                print(tempItems)
            }
        }
              
        groupedItems.append(tempItems)
        return groupedItems
    }
    
    var body: some View {
        ScrollView {
            VStack(alignment: .leading) {
                ForEach(groupedItems, id: \.self) { subWords in
                    HStack {
                        ForEach(subWords, id: \.self) { word in
                            Text(word)
                                .fixedSize()
                                .padding()
                                .background(backgroundColor)
                                .foregroundColor(foregroundColor)
                                .clipShape(RoundedRectangle(cornerRadius: 10.0, style: /*@START_MENU_TOKEN@*/.continuous/*@END_MENU_TOKEN@*/))
                                
                        }}
                    
                }
                Spacer()
                
            }.padding()
        }
    }
    
}
1 Answers

You are almost there.


Every Texts have 16 points padding on each of their sides. And the VStack has 16 points padding too. You need to consider them when calculating the width of the label.

let viewWidth = label.frame.size.width + 32

print("viewWidth = \(viewWidth)")
if (width + viewWidth + 32) < screenWidth {
    width += viewWidth
    print("width = \(width)")
    tempItems.append(word)
}


You may calculate the spacing between every two Texts too.

Related