【发布时间】: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来代替