在SwiftUI中,我如何使用另一个视图来剪切一个视图的一部分?

3
我正在尝试在SwiftUI中重叠两个圆,并在它们之间留有一定的间距。目前,我正在使用以下方法:
ZStack {
    Circle()
        .frame(width: 60, height: 60)
        .foregroundColor(Color.blue)
        .shadow(color: .black.opacity(0.5), radius: 4, x: 2, y: 2)
    ZStack {
        Circle()
            .frame(width: 26, height: 26)
            .foregroundColor(Color(.systemGray5))
        Circle()
            .frame(width: 22, height: 22)
            .foregroundColor(.blue)
    }
    .offset(x: 26, y: 17)
}

enter image description here

问题在于,由于大圆上的阴影,我永远无法完美地匹配小圆边界圆(即系统灰度5)。因此,虽然看起来还好,但我只想在圆之间显示边距。不是在小圆周围全部显示。
在Illustrator或其他方式中,我会使用26大小的圆形剪辑大图像,这样它看起来就像被咬了一口。然后我就可以完美地实现这种效果。
在SwiftUI中有没有办法裁剪我的大圆底部?
2个回答

6

这里是可能采用反向遮罩的演示(虽然简化了,但思路应该很清晰——去除硬编码和“咬合”位置计算由您负责)。

已在Xcode 13.2 / iOS 15.2上进行了测试。

演示

struct DemoView: View {
    struct BiteCircle: Shape {
        func path(in rect: CGRect) -> Path {
            let offset = rect.maxX - 26
            let crect = CGRect(origin: .zero, size: CGSize(width: 26, height: 26)).offsetBy(dx: offset, dy: offset)

            var path = Rectangle().path(in: rect)
            path.addPath(Circle().path(in: crect))
            return path
        }
    }
    var body: some View {
        ZStack {
            Circle()
                .frame(width: 60, height: 60)
                .foregroundColor(Color.blue)
                .mask(BiteCircle().fill(style: .init(eoFill: true)))     // << here !!
                .shadow(color: .black.opacity(0.5), radius: 4, x: 2, y: 2)

            Circle()
                .frame(width: 22, height: 22)
                .foregroundColor(.blue)
                .offset(x: 18, y: 18)
        }

    }
}

0

我认为这会很有帮助

extension View {
@inlinable
public func reverseMask<Mask: View>(
    alignment: Alignment = .center,
    @ViewBuilder _ mask: () -> Mask
) -> some View {
    self.mask {
        Rectangle()
            .overlay(alignment: alignment) {
                mask()
                    .blendMode(.destinationOut)
            }
    }
}

}

你可以这样使用它

ZStack {
        Circle().frame(width: 60, height: 60)
            .reverseMask { 
                Circle().frame(width: 25, height: 25)
                    .offset(x: 20, y: 20)
            }
        Circle().frame(width: 20, height: 20)
            .offset(x: 20, y: 20)
    }
    .foregroundColor(.blue)
    .shadow(color: .black, radius: 4)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接