尽管SwiftUI内置了多种选择,但如果我们愿意,也可以编写完全自定义的过渡。
该过程分三个步骤:
ViewModifier
来表示您处于任何状态的过渡。AnyTransition
扩展,将您的视图修饰符用于活动状态和身份状态。transition()
修饰符将该过渡应用于视图。例如,我们可以编写形状和视图修改器组合,以模仿 Keynote
中的 Iris
动画-它使新的幻灯片出现在向上增长的圆圈中,有点像旧的Looney Tunes
简介序列。
为了演示这一点,我将向您展示一个完整的代码示例,该示例执行以下操作:
ScaledCircle
形状,该形状在根据某些可动画化数据进行缩放的矩形内部创建一个圆。ViewModifier
结构,以将任何形状(在我们的示例中为缩放圆)应用为另一个视图的剪辑形状。AnyTransition
扩展中,以将该修饰符包装在过渡中,以便于访问。SwiftUI
视图以演示我们的过渡过程。这是代码,并附有注释以说明发生了什么:
struct ScaledCircle: Shape {
// 这可控制绘图矩形内部的圆的大小。
// 值为0时,圆圈是不可见的;
// 值为1时,圆圈将填充矩形。
var animatableData: CGFloat
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)
}
}
// 可以使用任何形状剪切任何视图的常规修改器。
struct ClipShapeModifier<T: Shape>: ViewModifier {
let shape: T
func body(content: Content) -> some View {
content.clipShape(shape)
}
}
// 结合了 ScaledCircle 和 ClipShapeModifier 的自定义过渡。
extension AnyTransition {
static var iris: AnyTransition {
.modifier(
active: ClipShapeModifier(shape: ScaledCircle(animatableData: 0)),
identity: ClipShapeModifier(shape: ScaledCircle(animatableData: 1))
)
}
}
// 使用我们的转场显示和隐藏红色矩形的示例视图移动。
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()
}
}
}
}