[英]Insertion/Removal animation in SwiftUI
我正在尝试实现此 animation 以在VStack
中插入元素,所有元素向下移动以为新元素创建空间,然后从右向左插入新元素。 下面的代码按照我的描述进行插入,但是如何使它也可以用于移除,animation 应该类似,元素被完全移除(向右),然后其他元素向上移动)
struct ContentView: View {
@State var show = false
var body: some View {
VStack {
show ? Rectangle().frame(width: 100, height: 100, alignment: .center)
.animation(Animation.easeIn(duration: 0.5).delay(1))
.transition(.move(edge: .trailing)): nil
Rectangle().frame(width: 100, height: 100, alignment: .center)
Rectangle().frame(width: 100, height: 100, alignment: .center)
Rectangle().frame(width: 100, height: 100, alignment: .center)
Rectangle().frame(width: 100, height: 100, alignment: .center)
Button("Add") {
show.toggle()
}
Spacer()
}.animation(Animation.easeIn(duration: 0.5))
}
}
我不确定您的最终结果到底应该是什么,而且我提出的解决方案并不是真正的“通用”,但它至少应该为您提供一个起点。
struct ContentView: View {
@State var show = false
@State var showPlaceholder = false
// The total animation duration will be twice as long as this value
private var animationDuration: TimeInterval = 0.5
var body: some View {
VStack {
ZStack {
if showPlaceholder {
Color.white.opacity(0.0)
.zIndex(1)
.frame(width: 100, height: 100)
}
if show {
Rectangle()
.zIndex(2)
.frame(width: 100, height: 100, alignment: .center)
.animation(Animation.easeIn(duration: animationDuration))
.transition(.move(edge: .trailing))
}
}
Rectangle().frame(width: 100, height: 100, alignment: .center)
Rectangle().frame(width: 100, height: 100, alignment: .center)
Rectangle().frame(width: 100, height: 100, alignment: .center)
Rectangle().frame(width: 100, height: 100, alignment: .center)
Button("Add") {
if show {
showPlaceholder(for: animationDuration)
show = false
}
else {
showPlaceholder(for: animationDuration) {
show = true
}
}
}
Spacer()
}.animation(Animation.easeIn(duration: animationDuration))
}
private func showPlaceholder(for timeInterval: TimeInterval, completion: (() -> Void)? = nil) {
showPlaceholder = true
Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: false) { (_) in
showPlaceholder = false
completion?()
}
}
}
如果你有那么多Rectangle()
,你应该使用ForEach
。 这将使添加和删除它们变得更加容易,因为您只需append
和removeLast
即可更改显示的数量。
这是我所做的:
Rectangle
的新结构added
的属性将控制是否显示Rectangle
RectangleInfo
数组ForEach
遍历rectangles
offset
代替transition
来更好地控制 animation。设置好 UI 后,就该制作动画了:
added
后,设置为 true 以便它滑入added
到 false 以将其滑出struct RectangleInfo: Identifiable { /// 1.
let id = UUID()
var added = true /// 2.
}
struct ContentView: View {
@State var rectangles = [ /// 3.
RectangleInfo(),
RectangleInfo(),
RectangleInfo()
]
let animationDuration = 0.5
var body: some View {
VStack {
ForEach(rectangles) { rectangle in /// 4.
Rectangle().frame(width: 100, height: 100, alignment: .center)
.offset(x: rectangle.added ? 0 : 200, y: 0) /// 5.
}
Button("Add") {
rectangles.append(RectangleInfo(added: false)) /// 6.
DispatchQueue.main.asyncAfter(deadline: .now() + animationDuration) {
rectangles[rectangles.count - 1].added = true /// 7.
}
}
Button("Remove") {
rectangles[rectangles.count - 1].added = false /// 8.
DispatchQueue.main.asyncAfter(deadline: .now() + animationDuration) {
rectangles.removeLast() /// 9.
}
}
Spacer()
}.animation(Animation.easeIn(duration: animationDuration))
}
}
结果:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.