2

UISearchDisplayControllerおよびそのドキュメントをすべて読んでいdelegateますが、検索条件が変更されたときにテーブル ビューをアニメーション化する方法が見つかりません。

私はこれらの2つの方法を使用しています: UISearchDisplayController メソッド

どちらも戻りYESますが、次のようなことを行う方法はまだ見つかりません: UITableView メソッド

重要かどうかはわかりませんが、 を使用NSfetchedResultsController しUITableViewUISearchDisplayController

それだけです ありがとう!

4

2 に答える 2

8

検索文字列または範囲が変更された場合は、フェッチされた結果コントローラーに新しいフェッチ要求を割り当てるため、呼び出しperformFetchて新しい結果セットを取得する必要があります。performFetchコントローラーの状態をリセットし、FRC デリゲート メソッドをトリガーしません。

そのため、フェッチ要求を変更した後、テーブル ビューを「手動で」更新する必要があります。ほとんどのサンプル プログラムでは、これは次のように行われます。

  • 検索テーブル ビューで呼び出すreloadData、または
  • またはYESから戻ります。shouldReloadTableForSearchStringshouldReloadTableForSearchScope

効果は同じです。アニメーションなしで検索テーブル ビューが再読み込みされます。

検索述語が変更されたときにテーブルビューの更新をアニメーション化する組み込み/簡単な方法はないと思います。ただし、次のことを試すことができます (これは単なるアイデアであり、実際に自分で試したことはありません)。

  • フェッチ リクエストを変更する前に、古い結果セットのコピーを作成します。

    NSArray *oldList = [[fetchedResultsController fetchedObjects] copy];
    
  • 新しいフェッチ要求を FRC に割り当て、 を呼び出しますperformFetch

  • 新しい結果セットを取得します。

    NSArray *newList = [fetchedResultsController fetchedObjects];
    
  • reloadData検索テーブル ビューを呼び出さないでください。

  • と を比較oldListnewListて、新しいオブジェクトと削除されたオブジェクトを検出します。insertRowsAtIndexPaths新しいオブジェクトとdeleteRowsAtIndexPaths削除されたオブジェクトを呼び出します。これは、両方のリストを並行してトラバースすることで実行できます。
  • またはNOから戻ります。shouldReloadTableForSearchStringshouldReloadTableForSearchScope

私が言ったように、これは単なるアイデアですが、うまくいくと思います。

于 2013-02-10T18:36:25.767 に答える
2

この質問は古いことは知っていますが、最近これに直面し、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で見つかったものpredicatesortDescriptors反映していfetchRequestます。
これらのプロパティのいずれかが設定されている場合、コントローラーは自動的に変更を計算し、デリゲートを介して送信するため、大きなコード変更がないことを願っています。アニメーションが必要ない場合でも、直接設定しpredicateたりsortDescriptorsfetchRequestそれ自体に設定したりできます。

于 2016-04-20T03:00:20.633 に答える