I have a RoundedRectangle
that could get pretty big on large screens, i.e. iPads or MacOS windows, and in that case a fixed cornerRadius
chosen for iPhone-size screens would seem inappropriate.
I've tried using a GeometryReader
to get the current available width and multiply it by a certain scale factor to get the cornerRadius, this approach works, but the use of GeometryReader
changes my layout (Probably because it takes up all the space available?).
My current approach:
GeometryReader { geometry in
let cornerRadius = geometry.size.width * 0.27
RoundedRectangle(cornerRadius: cornerRadius
.aspectRatio(5/7, contentMode: .fit)
}
I've found that applying a .aspectRatio()
modifier would solve the problem:
GeometryReader { geometry in
let cornerRadius = geometry.size.width * 0.27
RoundedRectangle(cornerRadius: cornerRadius)
.aspectRatio(5/7, contentMode: .fit)
}
.aspectRatio(5/7, contentMode: .fit)
But this workaround doesn't seem proper since I probably wouldn't have a fixed aspect ratio for the content inside the next time I'm in this situation.
Without a GeometryReader
:
The original layout
With GeometryReader
:
You can see that the vertical spacing between rectangles are a bit wider
(I'm new to StackOverflow, so I can't directly put images here yet...)
Is there a cleaner approach to prevent GeometryReader
from changing the layout or is there a cleaner way to make the cornerRadius proportional to the size of the RoundedRectangle
? Any help would be greatly appreciated!
You could create your own Shape
for this.
A Shape
must implement a path
function and this function is supplied with a CGRect
. This gives us the dimensions of the area being drawn into:
struct ProportionalRoundedRectangle: Shape {
let cornerFraction: CGFloat
func path(in rect: CGRect) -> Path {
let minSize = min(rect.width, rect.height)
let cornerSize = min(0.5, max(0, cornerFraction)) * minSize
return Path(
roundedRect: rect,
cornerSize: .init(width: cornerSize, height: cornerSize)
)
}
}
Example use:
VStack {
ProportionalRoundedRectangle(cornerFraction: 0.1)
.stroke(.blue, lineWidth: 3)
.frame(width: 200, height: 100)
ProportionalRoundedRectangle(cornerFraction: 0.25)
.stroke(.red, lineWidth: 3)
.frame(width: 200, height: 100)
.overlay {
ProportionalRoundedRectangle(cornerFraction: 0.4)
.fill(.green)
.padding()
}
}