UI学习: UISearchController基础了解和应用

📅 2026/8/12 20:34:10
UI学习: UISearchController基础了解和应用
文章目录UISearchController协议声明属性创建 UISearchController搜索栏的事件监听开始编辑时调用是否允许编辑是否允许结束编辑结束编辑时调用搜索框中内容发生变化时调用点击搜索按钮时调用UISearchControllerUISearchController是苹果提供的一个控制器专门用来管理搜索功能。它帮你做了三件事显示一个搜索框searchBar监听用户输入通知你去更新搜索结果协议首先, 需要遵守协议, 用于在搜索栏中输入后更新搜索结果UITableViewDataSource,UITableViewDelegate,UISearchResultsUpdatingUISearchResultsUpdating是用于当UISearchController中的搜索文本发生变化时通知搜索结果控制器更新结果的协议。只有一个方法updateSearchResultsForSearchController:。通常在里面获取searchBar.text然后根据文本过滤数据源刷新tableView。配合UISearchController的searchResultsUpdater属性使用。适用于动态过滤本地数据这里做一展示可以看到, 当用户在搜索框中输入、删除或修改文字时系统会自动调用该协议中唯一的方法- (void)updateSearchResultsForSearchController:(UISearchController *)searchController方法在这个方法中, 可以根据搜索框中的文本(UISearchController.searchBar.text) 来刷新UITableView 或者 UICollectionView声明属性// ViewController.minterfaceViewController()property(nonatomic,strong)UITableView*tableView;property(nonatomic,strong)UISearchController*searchController;property(nonatomic,strong)NSArrayNSString**allData;// 原始数据永远不动property(nonatomic,strong)NSArrayNSString**filteredData;// 显示用的数据end我们定义声明一个 UITableView 来实时显示我们的搜索结果, 并声明两个NSArray 来作为 UITableView的数据源, allData 用来存储全部的数据, filteredData 这用来存储根据搜索结果筛选的数据-(void)viewDidLoad{[superviewDidLoad];self.title搜索;// Do any additional setup after loading the view.// ① 准备数据self.allData[Apple,Banana,Cherry,Date,Fig,Grape];self.filteredDataself.allData;[selfsetupTableView];[selfsetupSearchController];if(available(iOS26.0,*)){self.navigationItem.preferredSearchBarPlacementUINavigationItemSearchBarPlacementStacked;self.navigationItem.searchBarPlacementAllowsToolbarIntegrationNO;// 设置不允许将UISearchController放在工具栏中,保证UISearchController在上方的导航栏中}}在iOS26之后, UISearchController 默认是添加到toolbar中的,也就是显示在屏幕的下方, 如果要想让 UISearchController 显示在导航栏中, 就需要添加以下代码, 用来规定UISearchController 的位置if(available(iOS26.0,*)){self.navigationItem.preferredSearchBarPlacementUINavigationItemSearchBarPlacementStacked;// 设置不允许将UISearchController放在工具栏中,保证UISearchController在上方的导航栏中self.navigationItem.searchBarPlacementAllowsToolbarIntegrationNO;}创建 UISearchControllerself.searchController[[UISearchController alloc]initWithSearchResultsController:nil];参数 initWithSearchResultsController 表示显示结果的页面,传 nil 表示在当前界面显示搜索结果注意,如果要跳转界面进行结果展示, 需要要将searchResultsUpdater 代理对象设置为要跳转的视图控制器,否则无法观察到搜索结果MyViewController*vc[[MyViewController alloc]init];UISearchController*searchController[[UISearchController alloc]initWithSearchResultsController:vc];searchController.searchResultsUpdatervc;// 设置结果更新代理这里展示跳转界面展示搜索结果设置UISearchController 的相关属性searchController.obscuresBackgroundDuringPresentationNO;// 搜索时是否模糊背景默认YESsearchController.hidesNavigationBarDuringPresentationNO;// 搜索时是否隐藏导航栏默认YESsearchController.searchBar.placeholder搜索;// 占位文字// searchController.searchBar.delegate self; // 可选监听搜索栏事件searchController.searchBar.returnKeyTypeUIReturnKeySearch;// 设置键盘样式self.searchController.searchBar.keyboardTypeUIKeyboardTypeDefault;然后设置tableView的相关属性, 用来显示搜索结果-(void)setupTableView{self.tableView[[UITableView alloc]initWithFrame:self.view.bounds];self.tableView.dataSourceself;[self.tableView registerClass:[UITableViewCell class]forCellReuseIdentifier:cell];[self.view addSubview:self.tableView];}这里我们设置的数组filteredData是根据搜索结果实时更新的, 所以我们实现协议方法返回cell的个数就返回数组filteredData.count另外在cell的注册和设置时, 我们就显示当前的搜索结果, 如果没有输入显示所有结果-(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section{returnself.filteredData.count;// 始终用 filteredData}-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{UITableViewCell*cell[tableView dequeueReusableCellWithIdentifier:cellforIndexPath:indexPath];cell.textLabel.textself.filteredData[indexPath.row];returncell;}另外, 还有一个更重要的部分,就是让数组 filteredData 根据搜索框中的内容实时更新, 这里就需要用到上面提到的 UISearchController 的协议方法,- (void)updateSearchResultsForSearchController:(UISearchController *)searchController,在搜索框中删除或输入内容,就筛选结果对 filteredData 进行更新代码如下:// 用户输入时自动调用-(void)updateSearchResultsForSearchController:(UISearchController*)searchController{NSLog(搜索框结果更新);NSString*textsearchController.searchBar.text;if(text.length0){// 没有输入显示全部self.filteredDataself.allData;}else{// 有输入过滤数据NSPredicate*predicate[NSPredicate predicateWithFormat:SELF CONTAINS[cd] %,text];self.filteredData[self.allData filteredArrayUsingPredicate:predicate];}// 刷新列表[self.tableView reloadData];}在上面的方法中, 用到了NSPredicate *predicate [NSPredicate predicateWithFormat:SELF CONTAINS[cd] %, text];, 这里使用了谓词, 由于笔者没有学习过谓词, 这里也不过多讲解, 就解释一下这段代码的意义这行代码创建了一个NSPredicate谓词对象用于测试一个字符串是否包含另一个子串不区分大小写和变音符号。它通常与NSArray的filteredArrayUsingPredicate:方法配合使用实现数组的模糊搜索过滤。用这行代码就实现了根据搜索框中的输入对结果进行筛选搜索栏的事件监听UISearchBarDelegate协议包含多个可选方法用于监听UISearchBar的各种交互事件。所以如果需要监听搜索栏的事件 就需要遵守UISearchBarDelegate协议, 还需要需要设置代理searchController.searchBar.delegateself;开始编辑时调用// 已经开始编辑键盘已弹出-(void)searchBarTextDidBeginEditing:(UISearchBar*)searchBar{NSLog(开始编辑);}是否允许编辑如果返回 NO, 则不会有键盘弹出-(BOOL)searchBarShouldBeginEditing:(UISearchBar*)searchBar{returnYES;}是否允许结束编辑-(BOOL)searchBarShouldEndEditing:(UISearchBar*)searchBar{returnYES;}如果返回 NO, 可以阻止收起键盘结束编辑时调用-(void)searchBarTextDidEndEditing:(UISearchBar*)searchBar{NSLog(已经结束编辑);}搜索框中内容发生变化时调用-(void)searchBar:(UISearchBar*)searchBar textDidChange:(NSString*)searchText{NSLog(遵守协议, 搜索框结果更新);}点击搜索按钮时调用-(void)searchBarSearchButtonClicked:(UISearchBar*)searchBar{NSLog(点击了搜索按钮);}完整代码如下://// ViewController.m// UISearchController//// Created by lose_sea on 2026/5/30.//#importViewController.h#importMyViewController.hinterfaceViewController()UITableViewDataSource,UISearchResultsUpdating,UISearchBarDelegate,UITableViewDelegate// ViewController.mproperty(nonatomic,strong)UITableView*tableView;property(nonatomic,strong)UISearchController*searchController;property(nonatomic,strong)NSArrayNSString**allData;// 原始数据永远不动property(nonatomic,strong)NSArrayNSString**filteredData;// 显示用的数据endimplementationViewController-(void)viewDidLoad{[superviewDidLoad];self.title搜索;// Do any additional setup after loading the view.[selfsetData];[selfsetupTableView];[selfsetupSearchController];if(available(iOS26.0,*)){self.navigationItem.preferredSearchBarPlacementUINavigationItemSearchBarPlacementStacked;// 设置不允许将UISearchController放在工具栏中,保证UISearchController在上方的导航栏中self.navigationItem.searchBarPlacementAllowsToolbarIntegrationNO;}}-(void)setData{// ① 准备数据self.allData[Apple,Banana,Cherry,Date,Fig,Grape];self.filteredDataself.allData;}-(void)setupSearchController{MyViewController*vc[[MyViewController alloc]init];UISearchController*searchController[[UISearchController alloc]initWithSearchResultsController:vc];searchController.searchResultsUpdatervc;// 设置结果更新代理searchController.obscuresBackgroundDuringPresentationYES;// 搜索时是否模糊背景默认YESsearchController.hidesNavigationBarDuringPresentationYES;// 搜索时是否隐藏导航栏默认YESsearchController.searchBar.placeholder搜索;// 占位文字searchController.searchBar.returnKeyTypeUIReturnKeySearch;self.searchControllersearchController;searchController.searchBar.delegateself;// 可选监听搜索栏事件// 将 searchBar 添加到导航栏self.navigationItem.searchControllersearchController;// 设置键盘样式self.searchController.searchBar.keyboardTypeUIKeyboardTypeDefault;// 可选滚动时保持 searchBar 在顶部self.navigationItem.hidesSearchBarWhenScrollingNO;UIBarButtonItem*item1[[UIBarButtonItem alloc]initWithTitle:backstyle:UIBarButtonItemStylePlain target:selfaction:selector(pressBtn)];self.navigationItem.rightBarButtonItemitem1;}-(void)pressBtn{NSLog(点击啦按钮);}-(void)setupTableView{self.tableView[[UITableView alloc]initWithFrame:self.view.bounds];self.tableView.dataSourceself;self.tableView.delegateself;[self.tableView registerClass:[UITableViewCell class]forCellReuseIdentifier:cell];[self.view addSubview:self.tableView];}// 用户输入时自动调用-(void)updateSearchResultsForSearchController:(UISearchController*)searchController{NSLog(搜索框结果更新);NSString*textsearchController.searchBar.text;if(text.length0){// 没有输入显示全部self.filteredDataself.allData;}else{// 有输入过滤数据NSPredicate*predicate[NSPredicate predicateWithFormat:SELF CONTAINS[cd] %,text];self.filteredData[self.allData filteredArrayUsingPredicate:predicate];}// 刷新列表[self.tableView reloadData];}-(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section{returnself.filteredData.count;// 始终用 filteredData}-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{UITableViewCell*cell[tableView dequeueReusableCellWithIdentifier:cellforIndexPath:indexPath];cell.textLabel.textself.filteredData[indexPath.row];returncell;}-(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath{[tableView deselectRowAtIndexPath:indexPath animated:YES];}#pragmamark-搜索栏事件监听// 询问是否允许开始编辑返回 NO 可阻止键盘弹出-(BOOL)searchBarShouldBeginEditing:(UISearchBar*)searchBar{returnYES;}// 已经开始编辑键盘已弹出-(void)searchBarTextDidBeginEditing:(UISearchBar*)searchBar{NSLog(开始编辑);}// 询问是否允许结束编辑返回 NO 可阻止收起键盘-(BOOL)searchBarShouldEndEditing:(UISearchBar*)searchBar{returnYES;}// 已经结束编辑键盘已收起-(void)searchBarTextDidEndEditing:(UISearchBar*)searchBar{NSLog(已经结束编辑);}// 搜索框内的文字每次改变时调用实时输入-(void)searchBar:(UISearchBar*)searchBar textDidChange:(NSString*)searchText{NSLog(遵守协议, 搜索框结果更新);}// 点击键盘上的“搜索”按钮returnKeyType 为 UIReturnKeySearch-(void)searchBarSearchButtonClicked:(UISearchBar*)searchBar{NSLog(点击了搜索按钮);}// 点击“书签”按钮需要设置 showsBookmarkButton YES-(void)searchBarBookmarkButtonClicked:(UISearchBar*)searchBar{NSLog(点击“书签”按钮);}// 点击“结果列表”按钮需要设置 showsResultsListButton YES已废弃-(void)searchBarResultsListButtonClicked:(UISearchBar*)searchBar{NSLog(点击了结果列表);}end