概述
秃头小码农们都知道,SwiftUI 不仅仅是一个静态 UI 构建框架那么简单,辅以海量默认或自定义的动画和过渡(Transition)特效,我们可以将 App 界面的绚丽升华到极致。
不过,目前 SwiftUI 中的过渡(Transition)动画在某些“敏感”场景中会有让人意想不到的效果,我们如何随机应变回归本源呢?本篇由此应运而生。
在本篇博文中,您将学到如下内容:
- 茫然若失:消失的 Transition 动画
- 什么是 Transition 过渡动画?
本文示例代码测试环境:macOS 15.2 + Xcode 16.1
百闻不如一见,那小伙伴们还等什么呢?让我们马上开始 Transition 动画除虫大冒险吧!
Let‘s go!!;)
1. 茫然若失:消失的 Transition 动画
这是一段非常简单的 SwiftUI 代码,我们在用户选中某个 WorryObject 对象时在对应视图的右上角显露出一个绿色的圆形标志:
@FetchRequest(sortDescriptors: [.init(keyPath: \WorryObject.name, ascending: false)]) var allWorryObjects: FetchedResults<WorryObject>
@State var selectingWorryObjectID: UUID?
@Namespace private var ns
DisclosureGroup("担忧对象") {
LazyVGrid(columns: [GridItem](repeating: .init(), count: 3)) {
ForEach(allWorryObjects) { wObject in
VStack {
Text(wObject.name ?? "")
.font(.title3.bold())
Text(wObject.level.title)
.font(.caption2)
.foregroundStyle(.gray)
.padding(.vertical, 8)
Text(wObject.type.title)
}
.contentShape(Rectangle())
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.overlay {
RoundedRectangle(cornerRadius: 10)
.stroke(.gray, lineWidth: selectingWorryObjectID == wObject.oid ? 3.0 : 1.0)
}
.overlay(alignment: .topTrailing) {
if selectingWorryObjectID == wObject.oid {
Image(systemName: "checkmark.circle.fill")
.foregroundStyle(.green.gradient)
.font(.title3.bold())
.transition(.scale)
.matchedGeometryEffect(id: 1, in: ns, isSource: selectingWorryObjectID == wObject.oid)
}
}
.onTapGesture {
withAnimation(.bouncy) {
if selectingWorryObjectID == wObject.oid {
selectingWorryObjectID = nil
} else {
selectingWorryObjectID = wObject.oid
}
}
}
.opacity(selectingWorryObjectID == wObject.oid ? 1.0 : 0.33)
}
}
.listRowSeparator(.hidden)
}
从上面代码可以清楚的看到,我们在绿色选中标志上应用了缩放(scale)过渡动画(transition)效果。
不过,如果在 Xcode 预览中仔细观察运行结果,我们会发现绿色选中标志在出现时没有任何动画效果(突然显现),只有在消失时才有一丝的动态点缀:
这是怎么回事呢?难道是 SwiftUI 过渡动画偶尔“发挥失常”?
2. 什么是 Transition 过渡动画?
SwiftUI 过渡(或称为转场)Transition 动画是普通动画的一种特殊形式,它们被专门用于描述视图是如何“从无到有或从有到无”的。
我们来看一段轻车简从的 SwiftUI 代码:
struct ContentView: View {
@State var magic = false
var body: some View {
NavigationStack {
VStack {
if magic {
Circle()
.foregroundStyle(.green.gradient)
.frame(width: 200, height: 200)
.transition(.scale)
}
}
.toolbar {
Button("Magic") {
withAnimation(.bouncy) {
magic.toggle()
}
}
}
}
}
}
上面这段简单的不能再简单的代码很好的诠释了 Transition 动画的特性:我们根据 magic 状态将一枚绿色的圆形从 SwiftUI 渲染树中插入或删除,并同时在它之上应用了缩放过渡动画。
在下篇博文中,我们将会继续讨论 SwiftUI 过渡动画的“阿格琉斯之踵”以及规避方法,敬请期待吧!
总结
在本篇博文中,我们简单介绍了什么是 SwiftUI 中的过渡(Transition)动画,以及它们在某些场景下会出现的一些小“故障”的表现。
感谢观赏,我们下篇再会吧!8-)