私が理解しているように、UISearchController
のデフォルトの動作は次のとおりです。
SearchResultsController
はこの時点まで表示されません。SearchResultsController
は、検索バーが空でない場合にのみ表示されます。検索バーが空であるが選択されている場合(つまり、上記のケース1)でもSearchResultsController
を表示したい。
簡単に言えば、背景を暗くする代わりに、検索結果を表示したいと思います。
これを行う方法はありますか?
詳細説明:
私はUISearchController
を使用して、それが表示されているビューに表示される結果をフィルター処理していませんが、他の無関係な結果をフィルター処理しています。 Facebookが「ニュースフィード」で行うことのようになります。検索バーをタップすると、最初に検索候補が表示され、その後、編集を開始すると、ニュースフィードに関連しない可能性のある検索結果が表示されます。
SearchBarがアクティブであるがテキストがない場合、基になるtableViewの結果が表示されます。それが組み込みの動作であり、その状態に対してsearchResultsControllerが非表示になっている理由です。
検索がアクティブでフィルタリングが行われていない場合の動作を変更するには、通常はまだ非表示になっているときにsearchResultsControllerを表示する必要があります。
<UISearchResultsUpdating>
およびupdateSearchResultsForSearchController:
を介してこれを達成する良い方法があるかもしれません。プロトコルを介して解決できる場合は、それが推奨される方法です。
それでも解決しない場合は、組み込みの動作をハッキングする必要があります。私はそれを推奨したり、それに頼ったりはしませんし、壊れやすくなりますが、そのオプションを選択した場合の答えは次のとおりです。
TableViewControllerが<UISearchControllerDelegate>
に準拠していることを確認し、追加します
self.searchController.delegate = self;
willPresentSearchController:
を実装します
- (void)willPresentSearchController:(UISearchController *)searchController
{
dispatch_async(dispatch_get_main_queue(), ^{
searchController.searchResultsController.view.hidden = NO;
});
}
これにより、searchResultsController
が非表示に設定された後にUISearchController
が表示されます。
didPresentSearchController:
を実装します
- (void)didPresentSearchController:(UISearchController *)searchController
{
searchController.searchResultsController.view.hidden = NO;
}
組み込みの動作を回避するより良い方法については、 malhal's answer 。を参照してください
単にUISearchResultsUpdating
プロトコルを実装し、結果コントローラービューをupdateSearchResultsForSearchController
に常に表示するように設定できます。
func updateSearchResultsForSearchController(searchController: UISearchController) {
// Always show the search result controller
searchController.searchResultsController?.view.hidden = false
// Update your search results data and reload data
..
}
これは、テキストなしで検索バーがアクティブになっている場合でもメソッドが呼び出されるため機能します。
PetahChristianソリューションを試しましたが、検索バーに最初にフォーカスしたときにプリロード結果が表示されましたが、何かを入力してクリアすると、プリロード結果は再表示されません。
別の解決策を思いつきました。 SearchResultsControllerにデリゲートを追加し、searchController.searchBar.textが空のときに呼び出すだけです。このようなもの:
SearchResultsController:
protocol SearchResultsViewControllerDelegate {
func reassureShowingList() -> Void
}
class FullSearchResultsViewController: UIViewController, UISearchResultsUpdating{
var delegate: SearchResultsViewControllerDelegate?
...
func updateSearchResultsForSearchController(searchController: UISearchController) {
let query = searchController.searchBar.text?.trim()
if query == nil || query!.isEmpty {
...
self.delegate?.reassureShowingList()
...
}
...
}
また、SearchControllerを含むコントローラーにデリゲートを追加します。
self.searchResultsController.delegate = self
func reassureShowingList() {
searchController.searchResultsController!.view.hidden = false
}
このようなトリッキーなことで、私はスレッジハンマーアプローチをお勧めします!それは、何かがそれを隠そうとするときを検出し、そうするとき、それを元に戻すことです。これは、KVO(Key Value Observing)を介して実行できます。これは、検索バーのすべての複雑さを処理する必要なく、何があっても機能します。申し訳ありませんが、コードは複雑ですが、KVOは古いスタイルのAPIですが、私のコードは推奨プラクティスに従います。 SearchResultsViewControllerにこれを置きます:
static int kHidden;
@implementation SearchResultsViewController
-(void)viewDidLoad{
[super viewDidLoad];
[self.view addObserver:self
forKeyPath:@"hidden"
options:(NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionOld)
context:&kHidden];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
// if it was our observation
if(context == &kHidden){
// if the view is hidden then make it visible.
if([[change objectForKey:NSKeyValueChangeNewKey] boolValue]){
self.view.hidden = NO;
}
}
else{
// if necessary, pass the method up the subclass hierarchy.
if([super respondsToSelector:@selector(observeValueForKeyPath:ofObject:change:context:)]){
[super observeValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}
}
}
- (void)dealloc
{
[self.view removeObserver:self forKeyPath:@"hidden"];
}
// Here have the rest of your code for the search results table.
@end
これは、テキストがクリアされているかどうかを含め、すべての場合に機能します。
最後に、検索がアクティブになったときにテーブルが灰色に白くフェードアウトしてから白にフェードアウトしないようにするには、これを使用します:
self.searchController.dimsBackgroundDuringPresentation = NO;
Swift 3バージョン:
searchResultController
がnilでなく、検索結果を表示するために別のTable View Controllerを使用している場合、そのTable View ControllerをUISearchResultUpdating
およびupdateSearchResults
関数に適合させることができます。ビューを再表示するだけです。
func updateSearchResults(for searchController: UISearchController) {
view.hidden = false
}
Swift 4バージョン:
func updateSearchResults(for searchController: UISearchController) {
view.isHidden = false
}
iOS 13用に更新
IOS13から、この動作のシステムAPIサポートを取得しました。プロパティshowsSearchResultsController = true
を設定できます
iOS 12以下の場合
私は最近UISearchController
に取り組んでいます。検索バーが空のときにsearchResultsController
に検索履歴を表示したい。したがって、searchResultsController
は、UISearchController
が表示されるたびに表示する必要があります。
ここでは、別のソリューションを使用して、カスタムビューでsearchResultsController
プロパティをオーバーライドするによってhidden
が常に表示されるようにします。
たとえば、私のsearchResultsController
はUITableViewController
です。 UITableView
のサブクラスとしてVisibleTableViewを作成し、UITableView
のsearchResultsController
カスタムクラスをVisibleTableViewに変更します。 xibまたはストーリーボードで。このようにして、私のsearchResultsController
はUISearchController
によって隠されることはありません。
ここの良い点:
KVOよりも実装が簡単です。
searchResultsController
を表示するための遅延はありません。 「updateSearchResults」デリゲートメソッドの非表示フラグを反転することはできますが、searchResultsController
を表示するのに遅延があります。
非表示フラグはリセットされないため、非表示と表示の間にUIのギャップ/ジャンプはありません。
Swift 3サンプルコード:
class VisibleTableView: UITableView {
override var isHidden: Bool {
get {
return false
}
set {
// ignoring any settings
}
}
}
Swift 2.3 @malhalのアプローチのバージョン:
class SearchResultsViewController : UIViewController {
var context = 0
override func viewDidLoad() {
super.viewDidLoad()
// Add observer
view.addObserver(self, forKeyPath: "hidden", options: [ .New, .Old ], context: &context)
}
deinit {
view.removeObserver(self, forKeyPath: "hidden")
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if context == &self.context {
if change?[NSKeyValueChangeNewKey] as? Bool == true {
view.hidden = false
}
} else {
super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
}
}
}
非表示にされているのは、検索結果コントローラーのビューです。したがって、非表示になっている場合はいつでも再表示するだけで十分です。検索結果コントローラーで次のように行うだけです。
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.view.isHidden = false
}
func updateSearchResults(for searchController: UISearchController) {
self.view.isHidden = false
// ... your other code goes here ...
}
これで、検索バーのテキストが空の場合でも、結果ビュー(つまり、テーブルビュー)が常に表示されます。
ところで、iOS Mailアプリはこのように動作し、それが実装されていると仮定します(Appleが秘密のプライベートUISearchController設定にアクセスできる場合を除く)。
[iOS 10およびiOS 11でテスト済み。以前のシステムではテストしませんでした。]
Swift 4バージョンの malhals answer :
class SearchController: UISearchController {
private var viewIsHiddenObserver: NSKeyValueObservation?
override func viewDidLoad() {
super.viewDidLoad()
viewIsHiddenObserver = self.searchResultsController?.view.observe(\.hidden, changeHandler: { [weak self] (view, _) in
guard let searchController = self else {return}
if view.isHidden && searchController.searchBar.isFirstResponder {
view.isHidden = false
}
})
}
}
[weak self]
。それ以外の場合は、保持サイクルを導入します。
私はサイモン・ワンの答えが本当に好きで、それと一緒に働きました。
カスタムクラスでUISearchControllerをサブクラス化します。
class CustomClass: UISearchController {
override var searchResultsController: UIViewController? {
get {
let viewController = super.searchResultsController
viewController?.view.isHidden = false
return viewController
}
set {
// nothing
}
}
}
また、コードのどこにもこれがないことを確認してください。
self.resultsSearchController.isActive = true
resultsSearchControllerは私のUISearchControllerです
結果を暗くしたくない場合は、dimsBackgroundDuringPresentation
プロパティをfalse
に設定します。
これにより、検索中に基になるコンテンツが淡色表示されないようになります。
SearchTextが空の場合でも結果を返すことを確認する必要があります。そうしないと、空のテーブルビューが表示されます。
私はこれに多くの時間を費やし、最終的に私が行った解決策は@malhalsのようなものですが、facebookのKVOControllerを使用することでコードの量が大幅に削減されます: https://github.com/facebook/KVOController 。ここでのもう1つの利点は、searchResultsControllerがUINavigationController
である場合、@ malhalのコードを追加するためだけにサブクラス化する必要がないことです。
// always show searchResultsController, even if text is empty
[self.KVOController observe:self.searchController.searchResultsController.view keyPath:@"hidden" options:NSKeyValueObservingOptionNew block:^(id observer, UIView* view, NSDictionary *change) {
if ([change[NSKeyValueChangeNewKey] boolValue] == YES) {
view.hidden = NO;
}
}];
self.searchController.dimsBackgroundDuringPresentation = NO;
最も簡単な方法は、この拡張機能でReactiveCocoaを使用することです https://github.com/ColinEberhardt/ReactiveTwitterSearch/blob/master/ReactiveTwitterSearch/Util/UIKitExtensions.Swift
presentViewController(sc, animated: true, completion: {
sc.searchResultsController?.view.rac_hidden.modify({ value -> Bool in
return false
})
} )
scはUISearchControllerです