在 SwiftUI 中将视图添加到层次结构时如何动画转换
How to animate transition when adding view to hierarchy in SwiftUI
我正在尝试构建“弹出窗口”视图的叠加层并制作进出动画。转出有效,但转入无效——添加弹出视图时它会突然出现(错误),但当删除弹出视图时它会向右滑出(正确)。在此代码中,当将弹出窗口添加到视图层次结构时,如何使弹出窗口滑入(从右侧)?
iOS14.
中的完整功能代码
import SwiftUI
struct ContentView: View {
var body: some View {
Popovers()
}
}
struct Popovers : View {
@State var popovers : [AnyView] = []
var body : some View {
Button("Add a view ...") {
withAnimation {
popovers += [new()]
}
}
.blur(radius: 0 < popovers.count ? 8 : 0)
.overlay(ZStack {
ForEach(0..<self.popovers.count, id: \.self) { i in
popovers[i]
.frame(maxWidth: .infinity, maxHeight: .infinity)
.blur(radius: (i+1) < popovers.count ? 8 : 0)
.transition(.move(edge: .trailing)) // works only when popover is removed
}
})
}
func new() -> AnyView {
let popover = popovers.count
return AnyView.init(
VStack(spacing: 64) {
Button("Close") {
withAnimation {
_ = popovers.removeLast()
}
}
.font(.largeTitle)
.padding()
Button("Add") {
withAnimation {
popovers += [new()]
}
}
.font(.largeTitle)
.padding()
Text("This is popover #\(popover)")
.font(.title)
.foregroundColor(.white)
.fixedSize()
}
.background(Color.init(hue: 0.65-(Double(3*popover)/100.0), saturation: 0.3, brightness: 0.9).opacity(0.98))
)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
extension View {
var asAnyView : AnyView {
AnyView(self)
}
}
解决方案是向容器中添加动画。测试 Xcode 12 / iOS 14.
struct Popovers : View {
@State var popovers : [AnyView] = []
var body : some View {
Button("Add a view ...") {
withAnimation {
popovers += [new()]
}
}
.blur(radius: 0 < popovers.count ? 8 : 0)
.overlay(ZStack {
ForEach(0..<self.popovers.count, id: \.self) { i in
popovers[i]
.frame(maxWidth: .infinity, maxHeight: .infinity)
.blur(radius: (i+1) < popovers.count ? 8 : 0)
.transition(.move(edge: .trailing))
}
}.animation(.default)) // << add animation to container
}
func new() -> AnyView {
let popover = popovers.count
return AnyView.init(
VStack(spacing: 64) {
Button("Close") {
_ = popovers.removeLast()
}
.font(.largeTitle)
.padding()
Button("Add") {
popovers += [new()]
}
.font(.largeTitle)
.padding()
Text("This is popover #\(popover)")
.font(.title)
.foregroundColor(.white)
.fixedSize()
}
.background(Color.init(hue: 0.65-(Double(3*popover)/100.0), saturation: 0.3, brightness: 0.9).opacity(0.98))
)
}
}
我正在尝试构建“弹出窗口”视图的叠加层并制作进出动画。转出有效,但转入无效——添加弹出视图时它会突然出现(错误),但当删除弹出视图时它会向右滑出(正确)。在此代码中,当将弹出窗口添加到视图层次结构时,如何使弹出窗口滑入(从右侧)?
iOS14.
中的完整功能代码import SwiftUI
struct ContentView: View {
var body: some View {
Popovers()
}
}
struct Popovers : View {
@State var popovers : [AnyView] = []
var body : some View {
Button("Add a view ...") {
withAnimation {
popovers += [new()]
}
}
.blur(radius: 0 < popovers.count ? 8 : 0)
.overlay(ZStack {
ForEach(0..<self.popovers.count, id: \.self) { i in
popovers[i]
.frame(maxWidth: .infinity, maxHeight: .infinity)
.blur(radius: (i+1) < popovers.count ? 8 : 0)
.transition(.move(edge: .trailing)) // works only when popover is removed
}
})
}
func new() -> AnyView {
let popover = popovers.count
return AnyView.init(
VStack(spacing: 64) {
Button("Close") {
withAnimation {
_ = popovers.removeLast()
}
}
.font(.largeTitle)
.padding()
Button("Add") {
withAnimation {
popovers += [new()]
}
}
.font(.largeTitle)
.padding()
Text("This is popover #\(popover)")
.font(.title)
.foregroundColor(.white)
.fixedSize()
}
.background(Color.init(hue: 0.65-(Double(3*popover)/100.0), saturation: 0.3, brightness: 0.9).opacity(0.98))
)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
extension View {
var asAnyView : AnyView {
AnyView(self)
}
}
解决方案是向容器中添加动画。测试 Xcode 12 / iOS 14.
struct Popovers : View {
@State var popovers : [AnyView] = []
var body : some View {
Button("Add a view ...") {
withAnimation {
popovers += [new()]
}
}
.blur(radius: 0 < popovers.count ? 8 : 0)
.overlay(ZStack {
ForEach(0..<self.popovers.count, id: \.self) { i in
popovers[i]
.frame(maxWidth: .infinity, maxHeight: .infinity)
.blur(radius: (i+1) < popovers.count ? 8 : 0)
.transition(.move(edge: .trailing))
}
}.animation(.default)) // << add animation to container
}
func new() -> AnyView {
let popover = popovers.count
return AnyView.init(
VStack(spacing: 64) {
Button("Close") {
_ = popovers.removeLast()
}
.font(.largeTitle)
.padding()
Button("Add") {
popovers += [new()]
}
.font(.largeTitle)
.padding()
Text("This is popover #\(popover)")
.font(.title)
.foregroundColor(.white)
.fixedSize()
}
.background(Color.init(hue: 0.65-(Double(3*popover)/100.0), saturation: 0.3, brightness: 0.9).opacity(0.98))
)
}
}