How to create a custom transition
About 3 min
How to create a custom transition 관련
SwiftUI by Example
Back to Home
How to create a custom transition | SwiftUI by Example
How to create a custom transition
Updated for Xcode 15
Although SwiftUI comes with a selection of transitions built in, it’s also possible to write entirely custom transitions if we want to.
The process takes three steps:
- Create a
ViewModifier
that represents your transition at any of its states. - Create an
AnyTransition
extension that uses your view modifier for active and identity states. - Apply that transition to your views using the
transition()
modifier.
For example, we could write a shape and view modifier combination that lets us mimic the Iris animation in Keynote – it causes a new slide to appear in a circle that grows upwards, a bit like the old Looney Tunes intro sequence.
To demonstrate this in action, I’m going to show you a complete code example that does several things:
- Defines a
ScaledCircle
shape that creates a circle inside a rectangle that is scaled according to some animatable data. - Create a custom
ViewModifier
struct to apply any shape (in our case, the scaled circle) as a clip shape for another view. - Wraps that in an
AnyTransition
extension to wrap that modifier in a transition for easier access. - Creates a SwiftUI view to demonstrate our transition in action.
Here’s the code, with added comments to explain what’s going on:
struct ScaledCircle: Shape {
// This controls the size of the circle inside the
// drawing rectangle. When it's 0 the circle is
// invisible, and when it’s 1 the circle fills
// the rectangle.
var animatableData: Double
func path(in rect: CGRect) -> Path {
let maximumCircleRadius = sqrt(rect.width * rect.width + rect.height * rect.height)
let circleRadius = maximumCircleRadius * animatableData
let x = rect.midX - circleRadius / 2
let y = rect.midY - circleRadius / 2
let circleRect = CGRect(x: x, y: y, width: circleRadius, height: circleRadius)
return Circle().path(in: circleRect)
}
}
// A general modifier that can clip any view using a any shape.
struct ClipShapeModifier<T: Shape>: ViewModifier {
let shape: T
func body(content: Content) -> some View {
content.clipShape(shape)
}
}
// A custom transition combining ScaledCircle and ClipShapeModifier.
extension AnyTransition {
static var iris: AnyTransition {
.modifier(
active: ClipShapeModifier(shape: ScaledCircle(animatableData: 0)),
identity: ClipShapeModifier(shape: ScaledCircle(animatableData: 1))
)
}
}
// An example view move showing and hiding a red
// rectangle using our transition.
struct ContentView: View {
@State private var isShowingRed = false
var body: some View {
ZStack {
Color.blue
.frame(width: 200, height: 200)
if isShowingRed {
Color.red
.frame(width: 200, height: 200)
.transition(.iris)
.zIndex(1)
}
}
.padding(50)
.onTapGesture {
withAnimation(.easeInOut) {
isShowingRed.toggle()
}
}
}
}
Similar solutions…
How to make views scroll with a custom transition | SwiftUI by Example
How to make views scroll with a custom transition
How to add and remove views with a transition | SwiftUI by Example
How to add and remove views with a transition
How to create and compose custom views | SwiftUI by Example
How to create and compose custom views
How to create custom animated drawings with TimelineView and Canvas | SwiftUI by Example
How to create custom animated drawings with TimelineView and Canvas
How to create custom bindings | SwiftUI by Example
How to create custom bindings