Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to hide clipped views in SwiftUI HStack

Tags:

Is there a possibility in SwiftUI to show only as many (fixed size) views in one row as fit without clipping, e.g. cutting of parts of the view.

Example Layout

 ----------------------------------------- 
|                                         |
|  -------     -------     -------     -------     -------
| | VIEW1 |   | VIEW2 |   | VIEW3 |   | VIEW4 |   | VIEW5 |
|  -------     -------     -------     -------     -------
|                                         |
 -----------------------------------------

In this example VIEW5 should be hidden, because it is completely out of bounds with respect to the parent view. This could be done with .clipped().

VIEW4 should also be completely hidden! Because if it would be shown, it must be cut off. All other views should be rendered normally.

SwiftUI Layout

This initial try has the following problems:

  • since the width of the itemView is much larger then the outer VStack, the leading edges are not aligned => ☑️ Solution
  • ❌The last view might be visible even if it is not fully on screen. This should be avoided.
struct DemoView: View {
    let items: [String]
    @State private var totalHeight = CGFloat.zero
    
    var body: some View {
        VStack(alignment: .leading) {
            Text("Demo View:")
            itemView
                .padding()
                .background(Color.green)
        }
    }
    
    private var itemView: some View {
        HStack {
            ForEach(items, id: \.self) { item in
                Text(item)
                    .lineLimit(1)
                    .fixedSize()
                    .padding(.all, 5)
                    .font(.body)
                    .background(Color.blue)
                    .foregroundColor(Color.white)
                    .cornerRadius(5)
            }
        }
        .frame(maxWidth: 350)
    }
}

#if DEBUG
struct DemoView_Previews: PreviewProvider {
    static var items: [String] = (2000..<2020).map(String.init)
//        .map { item in
//            Bool.random() ? item : item + item
//        }
    
    static var previews: some View {
        DemoView(items: items)
//            .previewLayout(.sizeThatFits)
    }
}
#endif

Wrong Layout Example

like image 671
Julian Kahnert Avatar asked Dec 15 '20 15:12

Julian Kahnert


1 Answers

Use clipped with alignment on HStack frame (tested with Xcode 12.1 / iOS 14.1)

private var itemView: some View {
    HStack {
        ForEach(items, id: \.self) { item in
            Text(item)
                .lineLimit(1)
                .fixedSize()
                .padding(.all, 5)
                .font(.body)
                .background(Color.blue)
                .foregroundColor(Color.white)
                .cornerRadius(5)
        }
    }
    .frame(maxWidth: 350, alignment: .leading)
    .clipped()
}
like image 155
Asperi Avatar answered Oct 12 '22 05:10

Asperi