我正在尝试使用UISearchController在地图视图中搜索目的地。我希望UISearchBar出现在导航栏中,但如果没有在右侧显示取消按钮,我似乎无法这样做:
这个取消按钮有时会消失,而我正在玩耍,但我现在无法显示它我的搜索表显示了我想要它:
我确信必定会有一些小问题,我有点做错,但是我无法理解它是什么......
self.resultsViewController = [UITableViewController new];
self.searchController = [[UISearchController alloc] initWithSearchResultsController:self.resultsViewController];
self.searchController.searchResultsUpdater = self;
self.searchController.hidesNavigationBarDuringPresentation = false;
self.searchController.delegate = self;
self.searchBar = self.searchController.searchBar;
self.searchBar.placeholder = self.stage.title;
self.searchBar.searchBarStyle = UISearchBarStyleMinimal;
self.definesPresentationContext = true;
self.navigationItem.titleView = self.searchBar;
self.resultsTableView = self.resultsViewController.tableView;
self.resultsTableView.dataSource = self;
self.resultsTableView.delegate = self;
答案 0 :(得分:20)
有一种更简单的方法......
对于iOS 8和UISearchController,请使用git push origin <branch>
中的此委托方法:
UISearchControllerDelegate
不要忘记将自己设为代表:func didPresentSearchController(searchController: UISearchController) {
searchController.searchBar.showsCancelButton = false
}
答案 1 :(得分:13)
Swift3 中的简单解决方案 - 我们需要使用 CustomSearchBar 而不使用取消按钮,然后覆盖新 CustomSearchController 中的相应属性:
class CustomSearchBar: UISearchBar {
override func setShowsCancelButton(_ showsCancelButton: Bool, animated: Bool) {
super.setShowsCancelButton(false, animated: false)
}}
class CustomSearchController: UISearchController {
lazy var _searchBar: CustomSearchBar = {
[unowned self] in
let customSearchBar = CustomSearchBar(frame: CGRect.zero)
return customSearchBar
}()
override var searchBar: UISearchBar {
get {
return _searchBar
}
}}
在MyViewController中,我使用这个新的自定义子类初始化和配置searchController:
var videoSearchController: UISearchController = ({
// Display search results in a separate view controller
// let storyBoard = UIStoryboard(name: "Main", bundle: Bundle.main)
// let alternateController = storyBoard.instantiateViewController(withIdentifier: "aTV") as! AlternateTableViewController
// let controller = UISearchController(searchResultsController: alternateController)
let controller = CustomSearchController(searchResultsController: nil)
controller.searchBar.placeholder = NSLocalizedString("Enter keyword (e.g. iceland)", comment: "")
controller.hidesNavigationBarDuringPresentation = false
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.searchBarStyle = .minimal
controller.searchBar.sizeToFit()
return controller
})()
它运作正常且顺畅
答案 2 :(得分:12)
根据评论更新
UISearchBar
有一个属性(请参阅Apple docs),它确定是否显示取消按钮:
self.searchBar.showsCancelButton = false;
但是,根据OP注释,这不起作用,因为searchController不断重新打开取消按钮。要避免这种情况,请创建UISearchBar的子类,并覆盖setShowsCancelButton
方法:
@implementation MySearchBar
-(void)setShowsCancelButton:(BOOL)showsCancelButton {
// Do nothing...
}
-(void)setShowsCancelButton:(BOOL)showsCancelButton animated:(BOOL)animated {
// Do nothing....
}
@end
为确保searchController使用此子类,我们还需要子类UISearchController
,并覆盖searchBar
方法以返回子类的实例。我们还需要确保新的searchBar激活searchController - 我已经选择使用UISearchBarDelegate
方法textDidChange
来实现此目的:
@interface MySearchController () <UISearchBarDelegate> {
UISearchBar *_searchBar;
}
@end
@implementation MySearchController
-(UISearchBar *)searchBar {
if (_searchBar == nil) {
_searchBar = [[MySearchBar alloc] initWithFrame:CGRectZero];
_searchBar.delegate = self;
}
return _searchBar;
}
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if ([searchBar.text length] > 0) {
self.active = true;
} else {
self.active = false;
}
}
@end
最后,更改代码以实例化此子类:
self.searchController = [[MySearchController alloc] initWithSearchResultsController:self.resultsViewController];
(您显然需要导入这些子类的相关头文件。)
答案 3 :(得分:1)
你可以这样做:
- (void)willPresentSearchController:(UISearchController *)searchController {
dispatch_async(dispatch_get_main_queue(), ^{
searchController.searchBar.showsCancelButton = NO;
}); }
答案 4 :(得分:0)
@pbasdf 的答案大部分都有效,但检查searchText
长度以确定UISearchController
是否有效可以为用户添加更多工作。如果用户点击清除按钮,或者删除搜索栏中唯一的字符,则会出现转角情况。这会将active
设置为NO
,这会自动调用resignFirstResponder
上的UISearchBar
。键盘将消失,如果用户想要更改文本或输入更多文本,则需要在搜索栏上再次点击。
相反,如果搜索栏不是第一个响应者(键盘未处于活动状态并显示),我只会将active
设置为NO
,因为这实际上是取消命令。
标记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
拆分为自己的类别,因为恕我直言,这些类别使类更清晰,更易于维护。如果您想将委托保留在主类接口/实现中,那么非常欢迎您这样做。
@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:
按钮。答案 5 :(得分:0)
我可以通过在几个UISearchBar
方法中调用setShowsCancelButton
来让UISearchBarDelegate
无需子类化,从而按行动进行操作:
我在textDidChange
和searchBarCancelButtonClicked
中将其称为。这是我的实现:
extension MyViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText.characters.isEmpty == false {
searchBar.setShowsCancelButton(true, animated: true)
// whatever extra stuff you need to do
} else {
searchBar.setShowsCancelButton(false, animated: true)
// whatever extra stuff you need to do
}
// whatever extra stuff you need to do
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.setShowsCancelButton(false, animated: false)
searchBar.text = nil
searchBar.resignFirstResponder()
tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
// whatever extra stuff you need to do
}
}