我一直在阅读有关UISearchDisplayController
它的所有文档,delegate
但是当搜索条件发生变化时,我找不到任何方法来为表格视图设置动画。
我正在使用这两种方法:
他们都回来了YES
,但仍然找不到任何方法来做类似的事情:
我不知道这是否重要,但我正在使用一个来NSfetchedResultsController
填充UITableView
UISearchDisplayController
就是这样,谢谢!
我一直在阅读有关UISearchDisplayController
它的所有文档,delegate
但是当搜索条件发生变化时,我找不到任何方法来为表格视图设置动画。
我正在使用这两种方法:
他们都回来了YES
,但仍然找不到任何方法来做类似的事情:
我不知道这是否重要,但我正在使用一个来NSfetchedResultsController
填充UITableView
UISearchDisplayController
就是这样,谢谢!
当搜索字符串或范围发生变化时,您为获取的结果控制器分配一个新的获取请求,因此必须调用performFetch
以获取新的结果集。performFetch
重置控制器的状态,并且不会触发任何 FRC 委托方法。
因此,必须在更改获取请求后“手动”更新表视图。在大多数示例程序中,这是由
reloadData
搜索表视图,或YES
从shouldReloadTableForSearchString
or返回shouldReloadTableForSearchScope
。效果是一样的:搜索表视图重新加载,没有动画。
我认为没有任何内置/简单的方法可以在搜索谓词更改时为表格视图更新设置动画。但是,您可以尝试以下方法(这只是一个想法,我自己并没有真正尝试过):
在更改获取请求之前,请复制旧结果集:
NSArray *oldList = [[fetchedResultsController fetchedObjects] copy];
将新的 fetch 请求分配给 FRC 并调用performFetch
.
获取新的结果集:
NSArray *newList = [fetchedResultsController fetchedObjects];
不要调用reloadData
搜索表视图。
oldList
并newList
检测新的和删除的对象。调用insertRowsAtIndexPaths
新对象和deleteRowsAtIndexPaths
已删除对象。这可以通过并行遍历两个列表来完成。NO
从shouldReloadTableForSearchString
或返回shouldReloadTableForSearchScope
。正如我所说,这只是一个想法,但我认为它可以工作。
我知道这个问题很老,但是我最近遇到了这个问题,并且想要一个无论如何NSFetchedResultsController
初始化都可以工作的解决方案。它基于上面@martin-r 的回答。
这是相应的要点:https ://gist.github.com/stephanecopin/4ad7ed723f9857d96a777d0e7b45d676
import CoreData
extension NSFetchedResultsController {
var predicate: NSPredicate? {
get {
return self.fetchRequest.predicate
}
set {
try! self.setPredicate(newValue)
}
}
var sortDescriptors: [NSSortDescriptor]? {
get {
return self.fetchRequest.sortDescriptors
}
set {
try! self.setSortDescriptors(newValue)
}
}
func setPredicate(predicate: NSPredicate?) throws {
try self.setPredicate(predicate, sortDescriptors: self.sortDescriptors)
}
func setSortDescriptors(sortDescriptors: [NSSortDescriptor]?) throws {
try self.setPredicate(self.predicate, sortDescriptors: sortDescriptors)
}
func setPredicate(predicate: NSPredicate?, sortDescriptors: [NSSortDescriptor]?) throws {
func updateProperties() throws {
if let cacheName = cacheName {
NSFetchedResultsController.deleteCacheWithName(cacheName)
}
self.fetchRequest.predicate = predicate
self.fetchRequest.sortDescriptors = sortDescriptors
try self.performFetch()
}
guard let delegate = self.delegate else {
try updateProperties()
return
}
let previousSections = self.sections ?? []
let previousSectionsCount = previousSections.count
var previousObjects = Set(self.fetchedObjects as? [NSManagedObject] ?? [])
var previousIndexPaths: [NSManagedObject: NSIndexPath] = [:]
previousObjects.forEach {
previousIndexPaths[$0] = self.indexPathForObject($0)
}
try updateProperties()
let newSections = self.sections ?? []
let newSectionsCount = newSections.count
var newObjects = Set(self.fetchedObjects as? [NSManagedObject] ?? [])
var newIndexPaths: [NSManagedObject: NSIndexPath] = [:]
newObjects.forEach {
newIndexPaths[$0] = self.indexPathForObject($0)
}
let updatedObjects = newObjects.intersect(previousObjects)
previousObjects.subtractInPlace(updatedObjects)
newObjects.subtractInPlace(updatedObjects)
var moves: [(object: NSManagedObject, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath)] = []
updatedObjects.forEach { updatedObject in
if let previousIndexPath = previousIndexPaths[updatedObject],
let newIndexPath = newIndexPaths[updatedObject]
{
if previousIndexPath != newIndexPath {
moves.append((updatedObject, previousIndexPath, newIndexPath))
}
}
}
if moves.isEmpty && previousObjects.isEmpty && newObjects.isEmpty {
// Nothing really changed
return
}
delegate.controllerWillChangeContent?(self)
moves.forEach {
delegate.controller?(self, didChangeObject: $0.object, atIndexPath: $0.fromIndexPath, forChangeType: .Move, newIndexPath: $0.toIndexPath)
}
let sectionDifference = newSectionsCount - previousSectionsCount
if sectionDifference < 0 {
(newSectionsCount..<previousSectionsCount).forEach {
delegate.controller?(self, didChangeSection: previousSections[$0], atIndex: $0, forChangeType: .Delete)
}
} else if sectionDifference > 0 {
(previousSectionsCount..<newSectionsCount).forEach {
delegate.controller?(self, didChangeSection: newSections[$0], atIndex: $0, forChangeType: .Insert)
}
}
previousObjects.forEach {
delegate.controller?(self, didChangeObject: $0, atIndexPath: previousIndexPaths[$0], forChangeType: .Delete, newIndexPath: nil)
}
newObjects.forEach {
delegate.controller?(self, didChangeObject: $0, atIndexPath: nil, forChangeType: .Insert, newIndexPath: newIndexPaths[$0])
}
delegate.controllerDidChangeContent?(self)
}
}
它在 上公开 2 个属性,NSFetchedResultsController
这些属性predicate
与.
当设置这些属性中的任何一个时,控制器将自动计算更改并通过委托发送它们,因此希望没有重大的代码更改。如果你不想要动画,你仍然可以直接设置或在本身上。 sortDescriptors
fetchRequest
predicate
sortDescriptors
fetchRequest