Home > Back-end >  SwiftUI - Double `.clipped()` modifier makes views disappear
SwiftUI - Double `.clipped()` modifier makes views disappear

Time:11-20

I have a view, DotView, which consists of 3 green circles Green circles disappear after sliding a bit
The green circles disappear. Green circles stay, but overflow the red border
The green circles stay. Green circles and red border both stay, but together they are not constrained to the blue border
The green circles stay.

Here's my code:

/// 3 green circles, constrained to a red border
struct DotView: View {
    var body: some View {
        HStack {
            ForEach(0..<3) { _ in
                Circle()
                    .fill(Color.green)
                    .frame(width: 100, height: 100)
            }
        }
        .frame(width: 250)
        .border(Color.red)
        .clipped() /// 1. make sure the green circles don't overflow
    }
}

/// container for horizontal dragging, with a blue border
struct ContentView: View {
    @State var offset = CGFloat(0)
    var body: some View {
        DotView()
            .padding() /// add a small gap between the red and blue borders
            .offset(x: offset, y: 0)
            .border(Color.blue)
            .clipped() /// 2. make sure `DotView` doesn't overflow the blue border
            .gesture(
                DragGesture(minimumDistance: 0) /// slide `DotView` left and right
                        .onChanged { offset = $0.translation.width }
            )
    }
}

The disappearing effect is very visible with ForEach, but occurs with other views too. For example, here's what happens when you replace the entire HStack with Circle().fill(Color.green).frame(width: 100, height: 100):

1 circle disappears after nearing the edge

Is there any way I can use clipped more than once, without getting weird side effects? How come they only disappear on the left side and not the right side? Or maybe, offset is what's causing problems?

CodePudding user response:

Looks like drawing optimisation (and yes looks like it originated by offset).

Anyway, here is a fix - use drawing group to fix content (tested with Xcode 13 / iOS 15):

var body: some View {
    DotView()
        .padding()
        .drawingGroup()               // << here !!
        .offset(x: offset, y: 0)
        .border(Color.blue)
        .clipped()
        .gesture(
            DragGesture(minimumDistance: 0) /// slide `DotView` left and right
                .onChanged { offset = $0.translation.width }
        )
}
  • Related