Consider this: adding a modifier to a view will return a new View
instance that wraps the previous instance. This is also why the order in which you add modifiers matters.
We can use this to our advantage: by adding a padding, then adding a background to our new View, we can create our own additional layers:
Image("cat")
.cornerRadius(7) // Inner corner radius
.padding(5) // Width of the border
.background(Color.primary) // Color of the border
.cornerRadius(10) // Outer corner radius
Results in:
You can even turn this in a ViewModifier to be reusable more easily:
struct RoundedEdge: ViewModifier {
let width: CGFloat
let color: Color
let cornerRadius: CGFloat
func body(content: Content) -> some View {
content.cornerRadius(cornerRadius - width)
.padding(width)
.background(color)
.cornerRadius(cornerRadius)
}
}
Using it would become:
Image("cat").modifier(RoundedEdge(width: 5, color: .black, cornerRadius: 20))
This workd for any SwiftUI View, like Text
:
Text("Some text")
.padding(15)
.background(Color.red)
.modifier(RoundedEdge(width: 5, color: .black, cornerRadius: 20))
Results in: