ConcentricRectangle and ContainerRelativeShape
What's the difference between ConcentricRectangle (new in iOS 26) and ContainerRelativeShape?
Both do the same for an inset rectangle, reducing the corner radius accordingly:
Both need to come near rounded corners of an outer rounded .containerShape, but ConcentricRectangle needs to be near an actual corner and will only round that corner by default: (ConcentricRectangle in red, ContainerRelativeShape in yellow):
The real difference becomes visible when moving the shape just in one direction a bit:
This shape is not that practical with only one corner rounded, but the uniform version ConcentricRectangle(corners: .concentric, isUniform: true) with all the other corners getting the same rounding is quite nice:
This is mostly useful to make views rounded according to the device bezel rounded corners because SwiftUI sets a container shape accordingly.
// » SwiftUI Garden
// » https://swiftui-garden.com/Shapes/ConcentricRectangle-and-ContainerRelativeShape
import SwiftUI
struct ConcentricShapeExample: View {
var body: some View {
ContainerExampleShape()
.overlay(alignment: .leading) {
ConcentricAndContainerRelativeRectangle()
.padding(.leading, 8)
}
.containerShape(RoundedRectangle(cornerRadius: 50))
}
}
struct ContainerExampleShape: View {
var body: some View {
Color.blue.opacity(0.3)
.frame(width: 300, height: 300)
.clipShape(RoundedRectangle(cornerRadius: 50))
}
}
struct ConcentricAndContainerRelativeRectangle: View {
var body: some View {
ZStack {
ConcentricRectangle()
.fill(Color.red.opacity(0.5))
ContainerRelativeShape()
.fill(Color.yellow.opacity(0.5))
}
.frame(width: 120, height: 120)
}
}
#Preview {
ConcentricShapeExample()
}
// » SwiftUI Garden
// » https://swiftui-garden.com/Shapes/ConcentricRectangle-and-ContainerRelativeShape
import SwiftUI
enum Experiment: String, CaseIterable, Identifiable {
case concentricRect
case scrollableConcentricRect
case uniformConcentricRect
case containerRelative
var title: String {
switch self {
case .concentricRect:
"concentricRect"
case .scrollableConcentricRect:
"concentricRect (scrollable)"
case .uniformConcentricRect:
"concentricRect (uniform)"
case .containerRelative:
"containerRelative"
}
}
var id: String {
self.rawValue
}
}
struct ConcentricShapeFullscreenExample: View {
@State var experiment: Experiment = .concentricRect
@State var showSheet = false
var body: some View {
Group {
switch experiment {
case .concentricRect:
ShapeView {
ConcentricRectangle()
}
case .scrollableConcentricRect:
ScrollView {
ShapeView {
ConcentricRectangle()
}
.frame(height: 1000)
}
case .uniformConcentricRect:
ShapeView {
ConcentricRectangle(corners: .concentric, isUniform: true)
}
case .containerRelative:
ShapeView {
ContainerRelativeShape()
}
}
}
.ignoresSafeArea()
.overlay {
VStack {
Picker("Experiment", selection: $experiment) {
ForEach(Experiment.allCases, id: \.self) { experiment in
Text(experiment.title).tag(experiment)
}
}
.menuStyle(.button)
.pickerStyle(.menu)
Button("Show Sheet") {
self.showSheet = true
}
}
.padding()
.glassEffect()
}
.sheet(isPresented: $showSheet) {
ConcentricShapeFullscreenExample()
}
}
}
struct ShapeView<S: Shape>: View {
@ViewBuilder let content: () -> S
var body: some View {
VStack {
HStack {
content()
.fill(Color.yellow)
.frame(height: 80)
.frame(maxWidth: .infinity)
content()
.fill(Color.orange)
.frame(height: 80)
.frame(maxWidth: .infinity)
}
content()
.fill(Color.green)
.frame(height: 80)
.frame(maxWidth: .infinity)
content()
.fill(Color.blue)
.frame(maxHeight: .infinity)
.frame(maxWidth: .infinity)
}
.padding()
}
}
#Preview {
ConcentricShapeFullscreenExample()
}