SwiftUI 中的插入/移除动画
Posted
技术标签:
【中文标题】SwiftUI 中的插入/移除动画【英文标题】:Insertion/Removal animation in SwiftUI 【发布时间】:2021-04-21 08:34:53 【问题描述】:我正在尝试实现此动画以在VStack
中插入元素,所有元素向下移动以为新元素创建空间,然后从右向左插入新元素。
下面的代码按照我的描述进行插入,但是如何使它也可以用于移除,动画应该类似,元素被完全移除(向右),然后其他元素向上移动)
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))
【问题讨论】:
【参考方案1】:如果你有那么多Rectangle()
s,你应该使用ForEach
。这将使添加和删除它们变得更加容易,因为您只需 append
和 removeLast
即可更改显示的数量。
这就是我所做的:
-
创建一个表示
Rectangle
的新结构
added
属性将控制是否显示Rectangle
定义将向用户显示的RectangleInfo
数组
使用ForEach
循环遍历rectangles
除了transition
,您可以使用offset
来更好地控制动画。
设置好 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))
结果:
【讨论】:
【参考方案2】:我不确定您的最终结果究竟应该是什么,而且我提出的解决方案并不是真正的“通用”,但它至少应该为您提供一个起点。
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?()
【讨论】:
以上是关于SwiftUI 中的插入/移除动画的主要内容,如果未能解决你的问题,请参考以下文章