Reputation: 442
Is there a way to fill an area tiling it with a custom shape? Like we can do with
Image("SomeImage")
.resizable(resizingMode: .tile)
but I want to be able to change the shape of an Image (like changing a circle size) I fill with dynamically. Something like an analogue of VisualBrush
with a propper TileMode
in WPF.
Using ForEach
+ HStack
/VStack
gives really poor performance.
Upvotes: 0
Views: 1183
Reputation: 257719
Image
has own content size, so can be tiled as-is, but Shape
by design has no own size and fill all provided rectangle, so it is needed to specify which size to use for tiles.
Here is possible solution. Tested with Xcode 12 / iOS 14
struct DemoShapeTiling: View {
var body: some View {
Rectangle().fill(Color.blue)
.tile(Circle(), of: CGSize(width: 40, height: 40))
.foregroundColor(.red)
.clipped()
}
}
struct TilingShape<S: Shape>: Shape {
let shape: S
let size: CGSize
func path(in rect: CGRect) -> Path {
var path = Path()
for x in stride(from: CGFloat.zero, to: rect.size.width, by: size.width) {
for y in stride(from: CGFloat.zero, to: rect.size.height, by: size.height) {
let r = CGRect(origin: CGPoint(x: x, y: y), size: size)
path.addPath(shape.path(in: r))
}
}
return path
}
}
extension View {
public func tile<S: Shape>(_ shape: S, of size: CGSize) -> some View {
self.overlay(TilingShape(shape: shape, size: size))
}
}
Upvotes: 1