【问题标题】:SwiftUI + Combine: how to assign data to a model with animationSwiftUI + Combine:如何将数据分配给带有动画的模型
【发布时间】:2021-07-28 12:24:25
【问题描述】:

我正在使用Combine 来获取用户在搜索字段中键入的匹配项。它在去抖动、去重和获取数据方面效果很好。但我无法为项目的条目设置动画。当匹配到达时,ObservedObject 会立即更新,并且 UI 已经显示匹配。我更愿意为匹配项设置动画。

我认为问题在于匹配是在assign 方法中设置的,缺少withAnimation。是否有可能以某种方式在Combine 管道中添加动画?我应该为此使用副作用吗?

代码如下:

class DictionarySearchViewModel: ObservableObject {        
        @Published var translationMatches = [TranslationMatch]()
        @Published var text: String = ""
        @Published var isLoading = true
        @Published var connectionError = false
        
        private var cancellable: AnyCancellable? = nil
        
        init() {
            cancellable = $text
                .debounce(for: .seconds(0.1), scheduler: DispatchQueue.main)
                .removeDuplicates()
                .map { [self] queryText -> AnyPublisher<[TranslationMatch], Never> in
                    
                    if queryText.count < 2 {
                        return Future<[TranslationMatch], Never> { promise in
                            promise(.success([TranslationMatch]()))
                        }
                        .eraseToAnyPublisher()
                    } else {
                            
                            return DictionaryService.sharedInstance()
                                .searchMatchesPublisher(queryText)
                                .retry(3)
                                .replaceError(with: [TranslationMatch]())
                                .eraseToAnyPublisher()
                        } else {
                            return Future<[TranslationMatch], Never> { promise in
                                promise(.success([TranslationMatch]()))
                            }
                            .eraseToAnyPublisher()
                        }
                    }
                }
                .switchToLatest()
                .eraseToAnyPublisher()
                .receive(on: DispatchQueue.main)
                .assign(to: \.translationMatches, on: self)
        }
}


struct DictionarySearchView: View {
    @ObservedObject var viewModel: DictionarySearchViewModel

    var body: some View {
        ScrollView(.vertical, showsIndicators: false) {
            VStack(alignment: .leading, spacing: 15) {
                ForEach(viewModel.translationMatches, id: \.id) { translationMatch in
                     Text(translationMatch.label)
                }
            }
        }
    }
}

【问题讨论】:

  • 不要使用.assign(to: \.translationMatches, on: self) - 它会创建对self 的强引用 - 改为使用assign(to:)。但是如果仍然不能使用动画,那么你可以使用sink 来代替

标签: ios swift swiftui combine


【解决方案1】:

ForEach 中的Text 上使用.animation.transition

 Text(translationMatch.label)
   .animation(.default)
   .transition(AnyTransition.move(edge: .top))
           

https://developer.apple.com/tutorials/swiftui/animating-views-and-transitions

【讨论】:

  • 你基本上是对的,但是动画修饰符应该在你指定一个过渡之后指定。在您上面编写的代码中,它将执行一个没有过渡的默认动画。
猜你喜欢
  • 2020-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-01
  • 1970-01-01
  • 2012-02-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多