【轉】如何基於UISearchController深度自定義搜尋UI
最近看UISearchController,看到這個小哥的文章內容不錯,就是格式實在沒有看下去的慾望,所以自己改了下,看的更清晰了點,原文可以看這裡。
一、搜尋功能我相信很多app都用得上,iOS系統提供做搜尋的類有那幾種呢?
1.UISearchBar,這個相信大多數開發者都用過,這個只是提供搜尋框,其實就是跟一個UITextField沒啥區別,只是在textfield封裝了多點內容。
2.UISearchDisplayController,這個玩意是iOS8之前,專門用來做搜尋功能,對的,它就是一個控制器,他為你提供蘋果那種搜尋風格的轉場動畫以及搜尋檢視顯示邏輯等,但是使用起來相對複雜。所以在iOS8這個類已經被拋棄了,而引申一個新的搜尋類,就是以下要介紹的UISearchController。
3.UISearchController,這個類其實跟UISearchDisplayController功能差不多,只是蘋果對其再進行了高階封裝,從而使用起來更加簡單了。
二、其實自己在搞UISearchController之前,我已經到網上找過一下相關的資料,發現網上寫的都是千遍一律,教你怎麼用,就我個人覺得,難的是你要在它基礎上去對改它的UI,這就要你對它的檢視層次結構要很清楚了,那我們下面來開始幹活吧。
我們首先看一下系統自帶的搜尋框是怎樣的。
normal狀態下的searchBar
這個是正常狀態下的搜尋框,但是那灰色的背景真是醜出翔了,試問有那個產品設計能接受這個樣式的搜尋框?我們再看下編輯狀態下的吧。
編輯無文字狀態下
從normal到edit狀態會有一個轉場動畫,雖然介面還是很醜,而我們需要的正式這個動畫,如果我們完全自定義的話還需要做這個動畫就未免有點複雜了。
編輯有文字狀態
當你輸入文字是,你發現它那個蒙版消失了,而展現新的檢視,沒錯,那個就是你自己的搜尋結果控制器檢視了,下面再詳細介紹。
三、看了上面幾張圖,我們大概知道UISearchController的互動大概怎樣。
那我們再進去標頭檔案看一下他的一些屬性和方法吧
它的指定初始化方法就是
- (instancetype)initWithSearchResultsController:(nullableUIViewController*)searchResultsController;
所以你能定製屬於你自己的搜尋結果view。當你傳nil的時候,預設是當前view就是搜尋結果view。
UISearchResultsUpdating -> 搜尋結果更新回撥的協議,實現裡面的方法就能更新搜尋邏輯了,這裡不詳細說,網上一大堆教這個的。
再說下比較常用的屬性吧
dimsBackgroundDuringPresentation -> 是否顯示灰色透明的蒙版,預設YES
hidesNavigationBarDuringPresentation -> 是否隱藏導航條,這個一般不需要管,都是隱藏的
searchResultsController -> 就是你初始化傳進去的搜尋結果VC
searchBar -> 它內部會建立一個搜尋框給你。
UISearchController就這幾個屬性了。我們看下先怎麼去用?
UISearchController *searchController= [[UISearchController alloc] init];
self.tableView.tableHeaderView=searchController.searchBar;
searchController.searchResultsUpdater=self;
searchController.searchBar.delegate=self;
searchController.searchBar.placeholder=@"搜尋"; // placeholder
[searchController.searchBar setSearchFieldBackgroundImage:[UIImagehcq_imageNamed:@"business_search_bg"] forState:UIControlStateNormal]; // 設定搜尋框內部textField的背景圖
[self.searchBar setBackgroundImage:@""] // 設定搜尋框背景圖,要跟上面的區分哦,兩者不一樣
[searchController.searchBar setImage:[UIImagehcq_imageNamed:@"business_search_icon"] for SearchBarIcon:UISearchBarIcon Searchstate:UIControlStateNormal];// 設定搜尋框內放大鏡圖片
searchController.searchBar.tintColor=KC_RGB_COLOR(225,225,225);// 設定搜尋框內按鈕文字顏色,以及搜尋游標顏色。
searchController.searchBar.barTintColor=HCQ_VIEW_BACKGROUND_COLOR;// 設定搜尋框背景顏色
// Get the instance of the UITextField of the search bar
// 用KVC修改placeholder文字顏色
UITextField*searchField = [self.searchBar valueForKey:@"_searchField"]; // 先取出textfield
// Change the search bar placeholder text color
[searchField setValue:self.searchBar.tintColorforKeyPath:@"_placeholderLabel.textColor"]; // 然後setValueForKey,搞定
[searchController.searchBar setValue:@"完成"forKey:@"_cancelButtonText"]; // 設定搜尋框那個取消按鈕文字
// 如果你不想要搜尋框的背景或者希望背景透明,你加上這句程式碼吧
[[[searchController.searchBar.subviews.firstObject subviews] firstObject] removeFromSuperview];// 直接把背景imageView幹掉。在iOS8,9是沒問題的,7沒測試過。
到這裡,UISearchBar的UI就自定義完畢,想了解UISearchBar層次結構的話,可以用Xcode執行後開啟那個檢視層次結構看一下就一目瞭然。
四、下面介紹怎樣定義編輯無文字狀態下的搜尋UI,例如微信點選搜尋框後會出現3個按鈕《朋友圈,文章,公眾號》。
要定義這些UI,那麼我們需要自定義一個自己的searchController了,建立一個類MySearchController繼承UISearchController。
首先我們重寫初始化方法
- (instancetype)initWithSearchResultsController:(UIViewController*)searchResultsController
{
MyResultViewController *resultVC = [[MyResultViewController alloc] init];
if(self= [super initWithSearchResultsController: resultVC]) {
[selfsetup];
}
returnself;
}
- (instancetype)init
{
MyResultViewController *resultVC = [[MyResultViewController alloc] init];
if(self= [super initWithSearchResultsController:resultVC]) {
[selfsetup];
}
returnself;
}
// 重寫init方法,好讓外部怎麼建立都是我們自己的搜尋結果控制器。外部使用不需要關心太多
// 可以把剛才自定義SearchBarUI程式碼放到內部了。
- (void)setup
{
self.searchBar.placeholder=@"搜尋商家";
[self.searchBarsetSearchFieldBackgroundImage:[UIImagehcq_imageNamed:@"business_search_bg"]forState:UIControlStateNormal];
[self.searchBarsetImage:[UIImagehcq_imageNamed:@"business_search_icon"]forSearchBarIcon:UISearchBarIconSearchstate:UIControlStateNormal];
self.searchBar.tintColor=KC_RGB_COLOR(225,225,225);
self.searchBar.barTintColor=HCQ_VIEW_BACKGROUND_COLOR;
// Get the instance of the UITextField of the search bar
UITextField*searchField = [self.searchBarvalueForKey:@"_searchField"];
// Change the search bar placeholder text color
[searchFieldsetValue:self.searchBar.tintColorforKeyPath:@"_placeholderLabel.textColor"];
[[[self.searchBar.subviews.firstObjectsubviews]firstObject]removeFromSuperview];
[self.searchBarsetValue:@"完成"forKey:@"_cancelButtonText"];
}
然後來到viewDidLoad方法,新增我們需要定義的UI。
例如我想加一個switch到中間
UISwitch*st = [UISwitch new];
[self.view addSubview:st];
st.center = self.view.center;
一般我們會這樣寫,執行後點選搜尋框進入編輯狀態,發現開關出來了,但是當你輸入文字的時候,開關還在顯示還能點選。這就神奇了。會不會是檢視層級不對呢?沒錯,就是檢視層級問題,SearchController.view內部還有一個containerView(其實就是那個蒙版),而SearchController是把搜尋結果控制器view新增到containerView上,所以開關跟containerView是同一層次,而且在containerView之上,所以不會消失。也可以開啟層次結果圖看一下。
我們可以新增一個屬性
@property(nonatomic,weak)UIView*containerView;
重寫get方法
- (UIView*)containerView
{
if(!_containerView) {
_containerView=self.view.subviews.firstObject;
_containerView.backgroundColor=HCQ_VIEW_BACKGROUND_COLOR;
}
return_containerView;
}
然後在viewdidload中新增開關的程式碼改一下
[self.containerView addSubview:st];
繼續執行,發現還是不行,還是不會消失,為什麼呢?我們知道view的subview有先後順序,後新增的越在上面,因為你的搜尋結果view先新增到containerView,開關是後面加的,固然開關還是能看到。所以,你不能直接add,正確姿勢是插入insert
[self.containerView insertSubview:st atIndex:0];
這樣就沒問題了。
再補充一點,如果你想改containerView的frame,可以在這個方法修改
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
}
如果想做一些轉場過度動畫,那麼重寫viewWillAppear、viewWillDisappear在裡邊做吧
例如
- (void)viewWillAppear:(BOOL)animated
{
[superviewWillAppear:animated];
// 修改textfield背景圖
[self.searchBar setSearchFieldBackgroundImage:[UIImagehcq_imageNamed:@"business_search_bg_highlighted"] forState:UIControlStateNormal];
}
- (void)viewWillDisappear:(BOOL)animated
{
[superviewWillDisappear:animated];
// 這裡再改回來
[self.searchBar setSearchFieldBackgroundImage:[UIImagehcq_imageNamed:@"business_search_bg"]forState:UIControlStateNormal];
}
如果當狀態為activity的時候想隱藏tabbar,建議實現UISearchControllerDelegate的代理方法
func willPresentSearchController(_searchController:UISearchController) {
tabBarController?.tabBar.isHidden=true
}
func willDismissSearchController(_searchController:UISearchController) {
tabBarController?.tabBar.isHidden=false
}
然後在viewwillAppear將tabbar再次隱藏,否則pop回來的時候又會出現
override func viewWillAppear(_animated:Bool) {
super.viewWillAppear(animated)
if searchController.isActive{
tabBarController?.tabBar.isHidden = true
}
}
如果想push的時候把搜尋框也跟著隱藏
那麼在導航的棧頂控制器寫下
definesPresentationContext = true
必須要在棧頂控制器寫,而且push下一個子控制器的時候也要在導航棧裡Push,否則會有莫名其妙的Bug
五、結語
基本上按照上面所說的就能自定義基於系統的,屬於自己風格的搜尋框了。用系統提供的轉場動畫還是挺好看的。定製起來也比較簡單,有這個需求的可以參考下我寫的這編文章。
相關文章
- 自定義修改系統預設ie搜尋
- 搜尋框UISearchController的使用及所遇到的坑UIController
- Nebula 基於 ElasticSearch 的全文搜尋引擎的文字搜尋Elasticsearch
- jQuery DataTables新增自定義多個搜尋條件jQuery
- layUI Table自定義工具欄和搜尋引數UI
- 直播軟體開發,自定義搜尋欄的圖示樣式和搜尋框
- elasticsearch實現基於拼音搜尋Elasticsearch
- 0基礎學演算法 搜尋篇第一講 深度優先搜尋演算法
- ybtoj:深度優先搜尋
- 基於Elasticsearch實現搜尋建議Elasticsearch
- Lucene : 基於Java的全文搜尋引擎Java
- 自建搜尋引擎-基於美麗雲
- 基於SpringBoot 、AOP與自定義註解轉義字典值Spring Boot
- 9個基於Java的搜尋引擎框架Java框架
- 大眾點評搜尋基於知識圖譜的深度學習排序實踐深度學習排序
- SAP UI 搜尋分頁技術UI
- 深度學習在攜程搜尋詞義解析中的應用深度學習
- ES 筆記十六:基於詞項和基於全文的搜尋筆記
- 小程式搜尋自定義關鍵詞功能關閉意欲何為?
- 我的Google自定義搜尋–電子書/電影/iOS技術GoiOS
- layui下拉框xm-select自定義搜尋使用方法UI
- Android 自定義UI元件AndroidUI元件
- [轉載] PHP 基於字典樹演算法實現搜尋聯想功能PHP演算法
- Solr搜尋基礎Solr
- 工作安排(dfs深度優先搜尋)
- 【深度解讀】App Store搜尋廣告APP
- 基於 Elasticsearch 的站內搜尋引擎實戰Elasticsearch
- 基於策略搜尋的強化學習方法強化學習
- 語義搜尋相關配置
- vue基於Element構建自定義樹Vue
- 自定義基於XML的驗證器XML
- 轉載:如何穩定地使用 Google 搜尋Go
- Android自定義view --Path 的高階用法之-搜尋按鈕動畫AndroidView動畫
- 強化學習(十八) 基於模擬的搜尋與蒙特卡羅樹搜尋(MCTS)強化學習
- BM42:語義搜尋與關鍵詞搜尋結合
- UI篇-自定義控制元件之基類UIControlUI控制元件
- 有贊基於ES的搜尋系統架構是如何演進的?架構
- 大快搜尋大資料基礎管理平臺功能深度解析大資料