SwiftUI add inverted mask

前端 未结 5 1221
醉话见心
醉话见心 2020-12-15 22:53

I\'m trying to add a mask to two shapes such that the second shape masks out the first shape. If I do something like Circle().mask(Circle().offset(…)), this has

5条回答
  •  -上瘾入骨i
    2020-12-15 23:03

    Using a mask such as in the accepted answer is a good approach. Unfortunately, masks do not affect hit testing. Making a shape with a hole can be done in the following way.

    extension Path {
        var reversed: Path {
            let reversedCGPath = UIBezierPath(cgPath: cgPath)
                .reversing()
                .cgPath
            return Path(reversedCGPath)
        }
    }
    
    struct ShapeWithHole: Shape {
        func path(in rect: CGRect) -> Path {
            var path = Rectangle().path(in: rect)
            let hole = Circle().path(in: rect).reversed
            path.addPath(hole)
            return path
        }
    }
    

    The trick is to reverse the path for the hole. Unfortunately Path does not (yet) support reversing the path out-of-the-box, hence the extension (which uses UIBezierPath). The shape can then be used for clipping and hit-testing purposes:

    struct MaskedView: View {
    
        var body: some View {
            Rectangle()
                .fill(Color.blue)
                .frame(width: 300, height: 100)
                .clipShape(ShapeWithHole())    // clips or masks the view
                .contentShape(ShapeWithHole()) // needed for hit-testing
        }
    }
    

提交回复
热议问题