我有一个 SwiftUI 视图,它根据状态换出某些控件。我正在尝试使用 MVVM,所以我的大部分/所有逻辑都被推到了视图模型中。我发现在执行修改@Published var视图模型上的a 的复杂操作时,View不会动画。
这是一个示例,其中视图模型中的 1.0 秒计时器模拟在更改@Published var值之前正在完成的其他工作:
struct ContentView: View {
@State var showCircle = true
@ObservedObject var viewModel = ViewModel()
var body: some View {
VStack {
VStack {
if showCircle {
Circle().frame(width: 100, height: 100)
}
Button(action: {
withAnimation {
self.showCircle.toggle()
}
}) {
Text("With State Variable")
}
}
VStack {
if viewModel.showCircle {
Circle().frame(width: 100, height: 100)
}
Button(action: {
withAnimation {
self.viewModel.toggle()
}
}) {
Text("With ViewModel Observation")
}
}
}
}
class ViewModel: ObservableObject {
@Published var showCircle = true
public func toggle() {
// Do some amount of work here. The Time is just to simulate work being done that may not complete immediately.
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { [weak self] _ in
self?.showCircle.toggle()
}
}
}
Run Code Online (Sandbox Code Playgroud)
在视图模型工作流的情况下,你withAnimation什么都不做,因为在这种情况下状态没有改变(它只是一个函数调用),只安排了计时器,所以你宁愿需要它
Button(action: {
self.viewModel.toggle() // removed from here
}) {
Text("With ViewModel Observation")
}
...
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { [weak self] _ in
withAnimation { // << added here
self?.showCircle.toggle()
}
}
Run Code Online (Sandbox Code Playgroud)
但是我宁愿建议重新考虑视图设计......就像
VStack {
if showCircle2 { // same declaration as showCircle
Circle().frame(width: 100, height: 100)
}
Button(action: {
self.viewModel.toggle()
}) {
Text("With ViewModel Observation")
}
.onReceive(viewModel.$showCircle) { value in
withAnimation {
self.showCircle2 = value
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用 Xcode 11.2 / iOS 13.2 测试
父视图为其子视图的隐藏和显示设置动画。.animation(.easeIn)如果您在第一个 VStack 的末尾放置一个(或 .easeOut 或任何您喜欢的内容),它应该按预期工作。
像这样...
struct ContentView: View {
@State var showCircle = true
@ObservedObject var viewModel = ViewModel()
var body: some View {
VStack {
VStack {
if showCircle {
Circle().frame(width: 100, height: 100)
}
Button(action: {
withAnimation {
self.showCircle.toggle()
}
}) {
Text("With State Variable")
}
}
VStack {
if viewModel.showCircle {
Circle().frame(width: 100, height: 100)
}
Button(action: {
withAnimation {
self.viewModel.toggle()
}
}) {
Text("With ViewModel Observation")
}
}
}.animation(.easeIn)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1106 次 |
| 最近记录: |