SwiftUI 中滚动视图中的动画过渡和内容
Animated transitions and contents within ScrollView in SwiftUI
我不是 SwiftUI 的老手,但我发布了几个中等复杂度的应用程序。不过,我不能说我完全理解它,我希望有更深入了解的人可以对这个问题有所了解:
我有一些内容想要打开和关闭,这与 .sheet() 不同,但我想要对其进行更多控制。这是一些 "reconstructed" 代码,但它应该能够抓住本质:
struct ContentView: View {
@State private var isShown = false
var body: some View {
GeometryReader { g in
VStack {
ZStack(alignment: .top) {
// This element "holds" the size
// while the content is hidden
Color.clear
// Content to be toggled
if self.isShown {
ScrollView {
Rectangle()
.aspectRatio(1, contentMode: .fit)
.frame(width: g.size.width) // This is a "work-around"
} // ScrollView
.transition(.move(edge: .bottom))
.animation(.easeOut)
}
} // ZStack
// Button to show / hide the content
Button(action: {
self.isShown.toggle()
}) {
Text(self.isShown ? "Hide" : "Show")
}
} // VStack
} // GeometryReader
}
}
它的作用是打开和关闭某些内容块(此处由 ScrollView 中的 Rectangle 表示)。发生这种情况时,内容视图会通过一些动画从底部移入进行转换。再次点击按钮时会发生相反的情况。
这段特定的代码按预期工作,但只是因为这一行:
.frame(width: g.size.width) // This is a "work-around"
这又需要一个额外的 GeometryReader,否则,内容的宽度会被动画化,产生不需要的效果(我发现的另一个 "fix"正在使用 .fixedSize() 修饰符,但是为了产生合理的效果,它需要内容采用自己的宽度,例如 Text)
我的问题是:是否可以在不使用 "fixes" 的情况下很好地转换封装在 ScrollView 中的内容?或者,是否有更优雅的修复方法?
对@Asperi 回答后的问题的快速补充:内容应保持动画效果。
你是我唯一的希望,
–巴格兰
这是一个解决方案(已更新body
w/o GeometryReader
)。使用 Xcode 11.4 / iOS 13.4
测试
var body: some View {
VStack {
ZStack(alignment: .top) {
// This element "holds" the size
// while the content is hidden
Color.clear
// Content to be toggled
if self.isShown {
ScrollView {
Rectangle()
.aspectRatio(1, contentMode: .fit)
.animation(nil) // << here !!
} // ScrollView
.transition(.move(edge: .bottom))
.animation(.easeOut)
}
} // ZStack
// Button to show / hide the content
Button(action: {
self.isShown.toggle()
}) {
Text(self.isShown ? "Hide" : "Show")
}
} // VStack
}
我不是 SwiftUI 的老手,但我发布了几个中等复杂度的应用程序。不过,我不能说我完全理解它,我希望有更深入了解的人可以对这个问题有所了解:
我有一些内容想要打开和关闭,这与 .sheet() 不同,但我想要对其进行更多控制。这是一些 "reconstructed" 代码,但它应该能够抓住本质:
struct ContentView: View {
@State private var isShown = false
var body: some View {
GeometryReader { g in
VStack {
ZStack(alignment: .top) {
// This element "holds" the size
// while the content is hidden
Color.clear
// Content to be toggled
if self.isShown {
ScrollView {
Rectangle()
.aspectRatio(1, contentMode: .fit)
.frame(width: g.size.width) // This is a "work-around"
} // ScrollView
.transition(.move(edge: .bottom))
.animation(.easeOut)
}
} // ZStack
// Button to show / hide the content
Button(action: {
self.isShown.toggle()
}) {
Text(self.isShown ? "Hide" : "Show")
}
} // VStack
} // GeometryReader
}
}
它的作用是打开和关闭某些内容块(此处由 ScrollView 中的 Rectangle 表示)。发生这种情况时,内容视图会通过一些动画从底部移入进行转换。再次点击按钮时会发生相反的情况。
这段特定的代码按预期工作,但只是因为这一行:
.frame(width: g.size.width) // This is a "work-around"
这又需要一个额外的 GeometryReader,否则,内容的宽度会被动画化,产生不需要的效果(我发现的另一个 "fix"正在使用 .fixedSize() 修饰符,但是为了产生合理的效果,它需要内容采用自己的宽度,例如 Text)
我的问题是:是否可以在不使用 "fixes" 的情况下很好地转换封装在 ScrollView 中的内容?或者,是否有更优雅的修复方法?
对@Asperi 回答后的问题的快速补充:内容应保持动画效果。 你是我唯一的希望,
–巴格兰
这是一个解决方案(已更新body
w/o GeometryReader
)。使用 Xcode 11.4 / iOS 13.4
var body: some View {
VStack {
ZStack(alignment: .top) {
// This element "holds" the size
// while the content is hidden
Color.clear
// Content to be toggled
if self.isShown {
ScrollView {
Rectangle()
.aspectRatio(1, contentMode: .fit)
.animation(nil) // << here !!
} // ScrollView
.transition(.move(edge: .bottom))
.animation(.easeOut)
}
} // ZStack
// Button to show / hide the content
Button(action: {
self.isShown.toggle()
}) {
Text(self.isShown ? "Hide" : "Show")
}
} // VStack
}