【发布时间】:2020-10-13 13:31:15
【问题描述】:
我有许多 SwapItem 结构,每个都有一个子 SwapItemChild。然后,使用 SwiftUI 的ForEach,我想显示每个SwapItem 的名称,称为项目视图,还包含一个以各自SwapItemChild 为颜色的圆圈,称为子视图。随后,我想交换两个项目的孩子,并让各自的孩子视图改变位置动画。这是受到this extensive tutorial 的其他示例的启发,但不是专门用于子视图交换。
我尝试使用matchedGeometryEffect 通过相应SwapItemChild 的ID 标识每个子视图来执行此操作。然而,这会导致一个跳跃的动画,其中只有顶部的子视图向下移动,而底部的子视图会瞬间跳到顶部。
功能示例代码如下。
// MARK: - Model
struct SwapItem: Identifiable {
let id = UUID()
let name: String
var child: SwapItemChild
}
struct SwapItemChild: Identifiable {
let id = UUID()
let color: Color
}
class SwapItemStore: ObservableObject {
@Published private(set) var items = [SwapItem(name: "Task 1", child: SwapItemChild(color: .red)),
SwapItem(name: "Task 2", child: SwapItemChild(color: .orange))]
func swapOuterChildren(){
let tmpChild = items[0].child
items[0].child = items[1].child
items[1].child = tmpChild
}
}
// MARK: - View
struct SwapTestView: View {
@StateObject private var swapItemStore = SwapItemStore()
@Namespace private var SwapViewNS
var body: some View {
VStack(spacing: 50.0) {
Button(action: swapItemStore.swapOuterChildren){
Text("Swap outer children")
.font(.title)
}
VStack(spacing: 150.0) {
ForEach(swapItemStore.items){ item in
SwapTestItemView(item: item, ns: SwapViewNS)
}
}
}
}
}
struct SwapTestItemView: View {
let item: SwapItem
let ns: Namespace.ID
var body: some View {
HStack {
Circle()
.fill(item.child.color)
.frame(width: 100, height: 100)
.matchedGeometryEffect(id: item.child.id, in: ns)
.animation(.spring())
Text(item.name)
}
}
}
matchedGeometryEffect 的正确实现是什么让这些子视图无缝交换位置?
【问题讨论】:
-
这不是这个工具的工作方式。
matchedGeometryEffect在 不同 层次结构中具有相同 ID 的两个视图之间工作。参见例如stackoverflow.com/a/64414233/12299030。 -
我没有从文档中解释该限制。 Apple:“如果在同一事务中插入一个视图,而另一个具有相同键的视图被删除,系统将在窗口空间中插入它们的框架矩形,以使其看起来有一个视图从其旧位置移动到新位置."。我认为我的方法是在新位置插入子视图并从旧位置删除它,因此应该可以与
matchedGeometryEffect一起使用。
标签: view swiftui transition