问题描述
让我们看一下以下代码片段:
struct ContentView: View {
@State private var isViewHidden: Bool = false
let data = [1,2,3,4,5,6,7]
public var body: some View {
vstack {
Button("Hide",action: {
withAnimation {
isViewHidden.toggle()
}
})
ForEach(data,id: \.self) { _ in
vstack {
Text("Foo")
if isViewHidden {
Text("Bar").animation(nil)
}
}.padding().background(Color.green)
}
}
}
}
我希望Text(“ Hide”)将使父vstack内部的位置动起来。 但是它会坚持到最后一个位置,然后从那里消失,并重新设置动画。是否有可能使该动画更自然,从而使其在其父级内部进行动画处理。
解决方法
问题在于Bar
是新的View
,因此会淡出或出现在其最终目的地,因此它的位置不会动起来,因为它先前不在屏幕上。
诀窍是始终将Bar
保持在屏幕上,而只需调整其opacity
。由于.offset
并不总是出现,因此Bar
用于防止视图增长。添加或删除空白文本视图Text(" ")
,以使视图像以前一样增长。
以下是可以使动画效果更好的解决方法:
struct ContentView: View {
@State private var isViewHidden: Bool = false
let data = [1,2,3,4,5,6,7]
public var body: some View {
VStack {
Button("Hide",action: {
withAnimation {
isViewHidden.toggle()
}
})
ForEach(data,id: \.self) { _ in
VStack {
ZStack {
Text("Foo")
Text("Bar")
.offset(y: 28)
.opacity(isViewHidden ? 0 : 1)
}
if !isViewHidden {
Text(" ")
}
}.padding().background(Color.green)
}
}
}
}
它在模拟器中运行:
解决方案2:使用.matchedGeometryEffect
这是一个使用.matchedGeometryEffect
在Text("Bar").frame(height: 0)
和Text("Bar")
之间进行动画处理的解决方案。
struct ContentView: View {
@Namespace var namespace
@State private var isViewHidden: Bool = false
let data = [1,7]
public var body: some View {
VStack {
Button("Hide") {
withAnimation {
isViewHidden.toggle()
}
}
ForEach(data,id: \.self) { id in
VStack {
Text("Foo")
if isViewHidden {
Text("Bar").frame(height: 0)
.matchedGeometryEffect(id: id,in: namespace)
} else {
Text("Bar")
.matchedGeometryEffect(id: id,in: namespace)
}
}
.padding().background(Color.green)
}
}
}
}