私の目標は、キャンセルボタンがUISearchControllerの検索バーに表示されないようにすることです。私は ISearchControllerサンプルコードを使用したAppleのテーブル検索 から始め、以下のコードの抜粋にあるようにキャンセルボタンを非表示にしました。ただし、ユーザーがテキストフィールドをタップしても、キャンセルボタンは表示されます。何か助けは?
override func viewDidLoad() {
super.viewDidLoad()
resultsTableController = ResultsTableController()
searchController = UISearchController(searchResultsController: resultsTableController)
searchController.searchResultsUpdater = self
searchController.searchBar.sizeToFit()
tableView.tableHeaderView = searchController.searchBar
searchController.searchBar.delegate = self
//Hide cancel button - added by me
searchController.searchBar.showsCancelButton = false
...
それを実現するには3つの方法があると思います。
searchController.searchBar.showsCancelButton = false
UISearchBarをサブクラス化し、layoutSubviewsをオーバーライドして、システムがそれを描画しようとしたときにそのvarを変更します。
キーボード通知に登録IKeyboardWillShowNotificationでコードを適用1。
もちろん、いつでも検索バーを実装できます。
IOS 8およびUISearchControllerの場合、UISearchControllerDelegate
から次のデリゲートメソッドを使用します。
func didPresentSearchController(searchController: UISearchController) {
searchController.searchBar.showsCancelButton = false
}
自分を代理人として設定することを忘れないでください:searchController.delegate = self
単にUISearchController
&UISearchBar
をサブクラス化します。
class NoCancelButtonSearchController: UISearchController {
let noCancelButtonSearchBar = NoCancelButtonSearchBar()
override var searchBar: UISearchBar { return noCancelButtonSearchBar }
}
class NoCancelButtonSearchBar: UISearchBar {
override func setShowsCancelButton(_ showsCancelButton: Bool, animated: Bool) { /* void */ }
}
次のgithubプロジェクトは、ソリューション2として提示されるUISearchBarをサブクラス化します。
https://github.com/mechaman/CustomSearchControllerSwift
さらに、UISearchControllerをサブクラス化して、検索バーをtableViewヘッダー以外の場所に配置できるようにします。
お役に立てれば。
これは、Swiftで思いついた最も簡単なソリューションでした。
カスタム検索コントローラー:
class CustomSearchController: UISearchController {
var _searchBar: CustomSearchBar
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
self._searchBar = CustomSearchBar()
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
override init(searchResultsController: UIViewController?) {
self._searchBar = CustomSearchBar()
super.init(searchResultsController: searchResultsController)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var searchBar: UISearchBar {
return self._searchBar
}
}
カスタム検索バー:
class CustomSearchBar: UISearchBar {
override func setShowsCancelButton(showsCancelButton: Bool, animated: Bool) {
// do nothing
}
}
これの最も重要な部分は、_searchBar
オブジェクトをinit
に1回挿入するか、格納されたプロパティ内に作成するか。
UISearchControllerをサブクラス化し、以下を実行するだけです。
class CustomSearchController: UISearchController {
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
searchBar.showsCancelButton = false
}
}
これは、キャンセルボタンの点滅の問題を解決するために思いついた最も簡単な解決策でした。
TL; DR:UISearchBar
をサブクラス化し、setShowsCancelButton:
およびsetShowsCancelButton:animated:
をオーバーライドすると、キャンセルボタンが非表示になります。
検索バーが最初のレスポンダーではない場合(キーボードがアクティブで表示されていない場合)は、active
をNO
に設定します。これは、実質的にcancelコマンド。
マーキングsearchController.searchBar.showsCancelButton = NO
はiOS 8では機能しないようです。私はテストしていませんiOS 9。
空ですが、完全にするためにここに配置されています。
@import UIKit;
@interface FJSearchBar : UISearchBar
@end
#import "FJSearchBar.h"
@implementation FJSearchBar
- (void)setShowsCancelButton:(BOOL)showsCancelButton {
// do nothing
}
- (void)setShowsCancelButton:(BOOL)showsCancelButton animated:(BOOL)animated {
// do nothing
}
@end
ここで、実際の変更を行います。 UISearchBarDelegate
を独自のカテゴリに分割しました。これは、IMHOのカテゴリにより、クラスがよりクリーンになり、保守が容易になるためです。デリゲートをメインクラスのインターフェイス/実装内に保持したい場合は、それを歓迎します。
@import UIKit;
@interface FJSearchController : UISearchController
@end
@interface FJSearchController (UISearchBarDelegate) <UISearchBarDelegate>
@end
#import "FJSearchController.h"
#import "FJSearchBar.h"
@implementation FJSearchController {
@private
FJSearchBar *_searchBar;
BOOL _clearedOutside;
}
- (UISearchBar *)searchBar {
if (_searchBar == nil) {
// if you're not hiding the cancel button, simply uncomment the line below and delete the FJSearchBar alloc/init
// _searchBar = [[UISearchBar alloc] init];
_searchBar = [[FJSearchBar alloc] init];
_searchBar.delegate = self;
}
return _searchBar;
}
@end
@implementation FJSearchController (UISearchBarDelegate)
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
// if we cleared from outside then we should not allow any new editing
BOOL shouldAllowEditing = !_clearedOutside;
_clearedOutside = NO;
return shouldAllowEditing;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
// hide the keyboard since the user will no longer add any more input
[searchBar resignFirstResponder];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (![searchBar isFirstResponder]) {
// the user cleared the search while not in typing mode, so we should deactivate searching
self.active = NO;
_clearedOutside = YES;
return;
}
// update the search results
[self.searchResultsUpdater updateSearchResultsForSearchController:self];
}
@end
注意すべきいくつかの部分:
BOOL
をプロパティの代わりにプライベート変数として使用しました。searchBar
が最初のレスポンダーであるかどうかを確認します。そうでない場合は、テキストが空で検索を行わないため、実際には検索コントローラーを非アクティブ化します。 本当に確認したい場合は、searchText.length == 0
を確認することもできます。searchBar:textDidChange:
はsearchBarShouldBeginEditing:
の前に呼び出されるため、この順序で処理しました。[self.searchResultsUpdater updateSearchResultsForSearchController:self];
をsearchBarSearchButtonClicked:
に移動することをお勧めします検索ボタン。UISearchControllerDelegateを使用します。
func willPresentSearchController(_ searchController: UISearchController) {
searchController.searchBar.setValue("", forKey:"_cancelButtonText")
}