I am trying to design a video trimmer view in SwiftUI as follows. This result is this. My question is whether I can have the middle part (i.e. everything except 20 points on the left and right and 5 points up and down) transparent so that I can show thumbnails behind them (perhaps by having a custom clip shape)?
var body: some View {
HStack(spacing: 10) {
Image(systemName: "chevron.compact.left")
.frame(height:70)
Spacer()
Image(systemName: "chevron.compact.right")
}
.foregroundColor(.black)
.font(.title3.weight(.semibold))
.padding(.horizontal, 7)
.padding(.vertical, 3)
.background(.yellow)
.clipShape(RoundedRectangle(cornerRadius: 7))
.frame(width: 300)
.onGeometryChange(for: CGFloat.self) { proxy in
proxy.size.width
} action: { width in
print("width = \(width)")
}
}
Instead of background
and then clipShape
, use background(_:in:fillStyle:)
. This allows you to specify a Shape
in which you want the background color to fill.
You can write a Shape
like this:
struct VideoTrimmerBackgroundShape: Shape {
func path(in rect: CGRect) -> Path {
RoundedRectangle(cornerRadius: 7)
.path(in: rect)
.subtracting(
RoundedRectangle(cornerRadius: 7)
.path(in: rect.insetBy(dx: 20, dy: 5))
)
}
}
I am simply subtracting the path created by an insetted rounded rectangle from a non-insetted one.
Then
.background(.yellow, in: VideoTrimmerBackgroundShape())
// you don't need clipShape anymore!
subtracting
is available since iOS 17. If you need to support a lower version, you can just add the smaller rounded rectangle as a subpath, but use even-odd filling.
struct VideoTrimmerBackgroundShape: Shape {
func path(in rect: CGRect) -> Path {
var p = RoundedRectangle(cornerRadius: 7)
.path(in: rect)
p.addPath(
RoundedRectangle(cornerRadius: 7)
.path(in: rect.insetBy(dx: 20, dy: 5))
)
return p
}
}
.background(.yellow, in: VideoTrimmerBackgroundShape(), fillStyle: .init(eoFill: true))