UIViewController 中的 UISearchController

Posted

技术标签:

【中文标题】UIViewController 中的 UISearchController【英文标题】:UISearchController in a UIViewController 【发布时间】:2014-10-17 03:51:44 【问题描述】:

我希望在 Swift 中创建与 Apple 地图应用程序类似的功能。无论如何要将 UISearchController 集成到常规视图中(即:不是 UITableView)。在连接的搜索栏内单击后,通过 Storyboard 拖放一个会导致崩溃。或者有什么方法可以用 UITableView 实现这个结果?

【问题讨论】:

【参考方案1】:

如果你想将 UISearchController 与非 UITableView 一起使用,我就是这样做的。

由于UISearchController 不(还!)IB 支持,您确实不需要在其中添加任何内容,例如UISearchBar

@interface UIViewControllerSubclass () <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, UISearchControllerDelegate, UISearchResultsUpdating>

@property (strong, nonatomic) UISearchController *searchController;

@end

@implementation UIViewControllerSubclass

- (void)viewDidLoad
        
    [super viewDidLoad];
    // Do any custom init from here...

    // Create a UITableViewController to present search results since the actual view controller is not a subclass of UITableViewController in this case
    UITableViewController *searchResultsController = [[UITableViewController alloc] init];

    // Init UISearchController with the search results controller
    self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];

    // Link the search controller
    self.searchController.searchResultsUpdater = self;

    // This is obviously needed because the search bar will be contained in the navigation bar
    self.searchController.hidesNavigationBarDuringPresentation = NO;

    // Required (?) to set place a search bar in a navigation bar
    self.searchController.searchBar.searchBarStyle = UISearchBarStyleMinimal;

    // This is where you set the search bar in the navigation bar, instead of using table view's header ...
    self.navigationItem.titleView = self.searchController.searchBar;

    // To ensure search results controller is presented in the current view controller
    self.definesPresentationContext = YES;

    // Setting delegates and other stuff
    searchResultsController.tableView.dataSource = self;
    searchResultsController.tableView.delegate = self;
    self.searchController.delegate = self;
    self.searchController.dimsBackgroundDuringPresentation = NO;
    self.searchController.searchBar.delegate = self;        


@end

我希望它足够工作:-)

那当然你至少需要实现 UITableViewDelegate、UITableViewDataSource、UISearchResultsUpdater 方法。

享受吧!

【讨论】:

谢谢!这帮助我最终过渡到 UISearchController!此外,您不一定要创建 UITableView 来显示项目。如果将 searchResultsController 设置为 nil,它将在当前视图中查找任何 TableView。 谢谢。我想澄清那些与我有类似问题的人,其中 UISearchBar 将作为 UIViewController tableView 标题视图(非 UITableViewController)的一部分消失。关键是self.definesPresentationContext = true (Swift)。这解决了它。 你必须继承 UITableViewController 并实现它自己的行为。【参考方案2】:

我自己想弄清楚UISearchController。将其设置为titleView 很方便,但在我的一个页面上,我不得不将searchBar 放在UIViewController 的顶部附近:

// Add a normal View into the Storyboard.
// Set constraints:
// - height: 44
// - leading and trailing so that it spans the width of the page
// - vertical position can be anywhere based on your requirements, like near the top
@IBOutlet weak var searchContainerView: UIView!

var searchResultsController = UISearchController()

override func viewDidLoad() 
    // TODO: set the searchResultsController to something
    let controller = UISearchController(searchResultsController: nil)
    // have the search bar span the width of the screen
    controller.searchBar.sizeToFit()
    // add search bar to empty View
    searchContainerView.addSubview(controller.searchBar)
    searchResultsController = controller


更新:

在一两个项目中实施UISearchController 后,我发现自己倾向于@adauguet 将搜索栏嵌入导航栏的方法。

这是 Swift 中的代码。不过,其中一个区别是它没有设置 searchBar 委托,因为 searchResultsUpdater 已经在侦听文本更改。

override func viewDidLoad() 
    super.viewDidLoad()
//        locationManager.delegate = self
//        locationManager.desiredAccuracy = kCLLocationAccuracyBest
//        locationManager.requestWhenInUseAuthorization()
//        locationManager.requestLocation()
    let locationSearchTable = storyboard!.instantiateViewControllerWithIdentifier("LocationSearchTable") as! LocationSearchTable
    resultSearchController = UISearchController(searchResultsController: locationSearchTable)
    resultSearchController?.searchResultsUpdater = locationSearchTable
    let searchBar = resultSearchController!.searchBar
    searchBar.sizeToFit()
    searchBar.placeholder = "Search for places"
    navigationItem.titleView = resultSearchController?.searchBar
    resultSearchController?.hidesNavigationBarDuringPresentation = false
    resultSearchController?.dimsBackgroundDuringPresentation = true
    definesPresentationContext = true

另外,我写了一篇博文,从头开始创建一个项目,该项目使用UISearchController 来显示地图搜索结果。它还可以执行您在地图项目中可能需要的其他操作,例如获取用户位置、放置图钉、将地标解析为单行地址,以及创建可将您带到 Apple 地图以获取行车路线的标注按钮。

http://www.thorntech.com/2016/01/how-to-search-for-location-using-apples-mapkit/

这篇博文很长,如果你只想跳到代码,这里是相关的 git repo:

https://github.com/ThornTechPublic/MapKitTutorial

【讨论】:

对我真的很有帮助! 这个 UI 结构正是我想要的。感谢分享! hidesNavigationBarDuringPresentation = v.important!【参考方案3】:

我在情节提要的视图控制器中添加了搜索栏和搜索显示控制器。视图控制器只包含搜索栏和搜索显示控制器,没有自己的 TableView。当您在视图控制器中添加搜索栏时,它会自动将您的视图控制器设置为委托。

现在搜索栏和搜索显示控制器有一个自己的表格视图,当您在框内单击并开始输入时,它会使用它来显示搜索结果。此表视图希望您的视图控制器提供 numberOfRowsInSection 和 cellForRowAtIndexPath 函数的实现,以便正确显示数据。

当你在没有这些的情况下运行你的项目并点击搜索栏内时,你会得到以下错误:-

tableView:numberOfRowsInSection:]:无法识别的选择器发送到实例 0x7fbf63449660 *** 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序

如果您看到,错误是在 numberOfRowsInSection 方法处。

更改您的视图控制器定义
class ViewController: UIViewController

class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource

并实现所需的方法是:-

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
    return UITableViewCell()


func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return 0

我刚刚在上述方法中添加了默认返回值。

现在,如果您在 searchviewdelegate 方法中过滤掉数据源,并在上述两种方法中正确设置行数和单元格信息,它应该可以工作。

希望这会有所帮助!

【讨论】:

非常感谢拉吉夫!这就像一个魅力。经过一周的努力,我正在取得进展。我不知道 SearchController 内置了自己的 tableview - 这非常整洁! 很高兴帮助并感谢您接受作为答案。如果你能这么好,我也将不胜感激! 还没有获得 15 名声望 :( 我会尽力记住当我这样做的时候再回来给你投票。再次感谢 :) 你说的是UISearchDisplayController吗?您一直在说“搜索显示控制器”,但该类在 ios 8 中已弃用。 答案指的是UISearchDisplayController(iOS 8 中已弃用)。虽然实现上述答案中的方法对于结果表的委托仍然是必要的,但它们并不是 iOS 8 中新的UISearchController 的全部情况。其余部分请参见adauguet 的答案。【参考方案4】:

我在从 UIViewController 中的 SearchDisplayController 转换到 ViewController 中的 SearchController 时遇到了一些麻烦,因为 SearchController 的实现不是那么直观。但是您可以将 SearchController 本身的搜索器添加到任何视图中。但是您不能设置约束,因为当您聚焦/选择它时搜索栏会向上移动(如果您知道如何在将约束添加到任何视图后将其设置为 seachController.searchbar,让我知道!)。下面我分享一个清单,我在 ViewController 中实现 SearchController 时发现它非常重要/有价值。

//您可以将搜索器添加到任何视图。它会自动向上移动以像魔术一样显示 tableView。但是由于这个原因,您不能将搜索栏的约束设置为要添加到的占位符视图。

[self.searchBarPlaceHolderView addSubview:self.searchController.searchBar];

//当你聚焦/选择它时,你需要这个来防止搜索栏下拉。如果要将 searchBar 添加到导航栏的标题视图,则需要将其设置为 NO。

self.searchController.hidesNavigationBarDuringPresentation = YES;

//确保你在 viewController 中设置了这个

self.extendedLayoutIncludesOpaqueBars = true;
self.definesPresentationContext = YES;

// 你还需要给搜索控制器一个可以显示的tableViewController。你也可以只用 self.searchResultsController = [[UITableView alloc] init] 来做一个通用的。

self.searchResultsController = (UITableViewController *)[ [UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"searchResultsTableViewController"];

self.searchResultsController.tableView.dataSource = self;
self.searchResultsController.tableView.delegate = self;
self.searchResultsController.definesPresentationContext = NO;
self.searchController = [[UISearchController alloc] initWithSearchResultsController:self.searchResultsController];

【讨论】:

您的问题解决了吗?我目前在这方面遇到了一些困难

以上是关于UIViewController 中的 UISearchController的主要内容,如果未能解决你的问题,请参考以下文章

Swift - 从 NavigationController 中的 UIViewController 转到 TabBarController 中的 UIViewController

UIViewController 中的 UITableView - 将单元格连接到 UIViewController

UIViewControllers 中的 UIViewController

如何从创建的 UIViewController 中的另一个 UIViewController 执行功能

故事板中的 UIViewController 容器

从 swiftUI 中的一个嵌入式 UIViewController 导航到 swift UI 中的另一个嵌入式 UIViewcontroller