SwiftUI - 双“.clipped()”修饰符使视图消失

SwiftUI - Double `.clipped()` modifier makes views disappear

我有一个视图,DotView,它由 3 个绿色圆圈组成 clipped by a red border. I'm using DragGesture 在容器视图中水平滑动它,它有一个蓝色边框,也是 clipped

问题是,一旦我滑到某个点,3个绿色圆圈就消失了。 如何防止它们消失? 有趣的是,如果我删除第一个 clipped 并且只剪下蓝色容器,圆圈不会消失。同样,如果我删除第二个 clipped 并且只删除剪辑 DotView,它们也不会消失。

Both views clipped Only blue view clipped Only DotView clipped

The green circles disappear.

The green circles stay.

The green circles stay.

这是我的代码:

/// 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 = [=10=].translation.width }
            )
    }
}

消失效果在 ForEach 中非常明显,但在其他视图中也会出现。例如,将整个 HStack 替换为 Circle().fill(Color.green).frame(width: 100, height: 100) 时会发生以下情况:

有什么方法可以多次使用 clipped 而不会产生奇怪的副作用?为什么它们只在左侧消失而不在右侧消失? 或者,offset 是什么导致了问题?

看起来像是绘图优化(是的,看起来它是由 offset 发起的)。

无论如何,这里有一个修复 - 使用绘图组修复内容(使用 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 = [=10=].translation.width }
        )
}