UISearchController 定制UI(Swift)

以下內(nèi)容是在 Swift 4.0马澈,iOS 11 下的運行結果

默認樣式

初始化一個 UISearchController,并將 searchBar 設置為 tableView 的 headerView 時飞傀,如以下代碼:

let searchController = UISearchController.init(searchResultsController: nil)
tableView.tableHeaderView = searchController.searchBar

此時的樣式為:

默認樣式 高亮
1
0

自定義

下面我們通過修改 searchController 的 searchBar 屬性來調整樣式织鲸。

1. searchBarStyle

搜索框樣式

public enum UISearchBarStyle : UInt {    
    case `default` // 默認樣式媚狰,和 UISearchBarStyleProminent 一樣
    case prominent // 顯示背景,常用在my Mail, Messages and Contacts
    case minimal // 不顯示背景诱篷,系統(tǒng)自帶的背景色無效壶唤,自定義的有效,常用在Calendar, Notes and Music
}

用例:

let searchBar = searchController.searchBar
searchBar.searchBarStyle = .default
searchBarStyle 非活躍 活躍
default
prominent
minimal
2. tintColor

風格顏色棕所,可用于修改:

  • 輸入框的光標顏色
  • 取消按鈕字體顏色
  • 選擇欄被選中時的顏色
let searchBar = searchController.searchBar
searchBar.tintColor = .red
非活躍 活躍
3. barTintColor

搜索框背景顏色

let searchBar = searchController.searchBar
searchBar.barTintColor = .orange
非活躍 活躍
4. backgroundImage

搜索框背景圖片

createImage(_:size:) 方法為創(chuàng)建一個指定顏色闸盔,指定 size 的圖片。

let searchBar = searchController.searchBar
searchBar.backgroundImage = self.createImage(UIColor.red, size: CGSize.init(width: 200, height: 100))
非活躍 活躍
5. 設置(獲瘸鹊省)搜索框背景圖片

可以通過以下方式設置(獲壤倥埂)搜索框背景圖片:

// 設置
// Use UIBarMetricsDefaultPrompt to set a separate backgroundImage for a search bar with a prompt
func setBackgroundImage(_ backgroundImage: UIImage?, for barPosition: UIBarPosition, barMetrics: UIBarMetrics) 
// 獲取
open func backgroundImage(for barPosition: UIBarPosition, barMetrics: UIBarMetrics) -> UIImage?
public enum UIBarMetrics : Int {
    case `default`
    case compact
    case defaultPrompt // Applicable only in bars with the prompt property, such as UINavigationBar and UISearchBar
    case compactPrompt

    @available(iOS, introduced: 5.0, deprecated: 8.0, message: "Use UIBarMetricsCompact instead")
    public static var landscapePhone: UIBarMetrics { get }

    @available(iOS, introduced: 7.0, deprecated: 8.0, message: "Use UIBarMetricsCompactPrompt")
    public static var landscapePhonePrompt: UIBarMetrics { get }
}

@available(iOS 7.0, *)
public enum UIBarPosition : Int {
    case any

    case bottom // The bar is at the bottom of its local context, and directional decoration draws accordingly (e.g., shadow above the bar).

    case top // The bar is at the top of its local context, and directional decoration draws accordingly (e.g., shadow below the bar)

    case topAttached // The bar is at the top of the screen (as well as its local context), and its background extends upward—currently only enough for the status bar.
}

用例:

let searchBar = searchController.searchBar
searchBar.setBackgroundImage(createImage(.blue, size: CGSize.init(width: 20, height: 20)), for: .any, barMetrics: .default)
默認樣式 高亮
6. 文本框的背景圖片
open func setSearchFieldBackgroundImage(_ backgroundImage: UIImage?, for state: UIControlState)

open func searchFieldBackgroundImage(for state: UIControlState) -> UIImage?
let searchBar = searchController.searchBar
searchBar.setSearchFieldBackgroundImage(createImage(UIColor.yellow, size: CGSize.init(width: 200, height: 40)), for: .normal)
默認樣式 高亮
7. barStyle

搜索框風格 barStyle 的類型為 UIBarStyle,定義如下:

public enum UIBarStyle : Int {
    case `default`
    case black
}

用例:

let searchBar = searchController.searchBar
searchBar.barStyle = .black
barStyle 非活躍 活躍
default
1
0
black
9
10
8. showsBookmarkButton

是否顯示搜索框右側的圖書按鈕岛啸。

open var showsBookmarkButton: Bool // default is NO
barStyle 非活躍 活躍
false
true
9. showsCancelButton

是否顯示搜索框右側的取消按鈕钓觉。

open var showsCancelButton: Bool // default is NO
showsCancelButton 默認樣式 高亮
false
true
10. showsSearchResultsButton

是否顯示搜索框右側的搜索結果按鈕

open var showsSearchResultsButton: Bool // default is NO
showsSearchResultsButton 非活躍 活躍
false
true
11. isSearchResultsButtonSelected

設置搜索結果按鈕為選中狀態(tài):

open var isSearchResultsButtonSelected: Bool // default is NO

用例:

let searchBar = searchController.searchBar
searchBar.showsSearchResultsButton = true
searchBar.isSearchResultsButtonSelected = true
isSearchResultsButtonSelected 非活躍 活躍
false
true
12. searchFieldBackgroundPositionAdjustment

設置輸入框背景偏移量:

open var searchFieldBackgroundPositionAdjustment: UIOffset

用例:

let searchBar = searchController.searchBar
searchBar.searchFieldBackgroundPositionAdjustment = UIOffset.init(horizontal: 16, vertical: 16)
默認樣式 高亮
設置前
設置后
13. searchTextPositionAdjustment

設置輸入框文本偏移量:

open var searchTextPositionAdjustment: UIOffset

用例:

let searchBar = searchController.searchBar
searchBar.searchTextPositionAdjustment = UIOffset.init(horizontal: 16, vertical: 16)
默認樣式 高亮
設置前
設置后
14. 設置(獲取)搜索框的圖標

可以設置(獲燃岵取)的搜索框圖標包括:

  • 搜索圖標
  • 清除輸入的文字的圖標
  • 圖書圖標
  • 搜索結果列表圖標
open func setImage(_ iconImage: UIImage?, for icon: UISearchBarIcon, state: UIControlState)

open func image(for icon: UISearchBarIcon, state: UIControlState) -> UIImage?

用例:

let searchBar = searchController.searchBar
searchBar.showsBookmarkButton = true

let searchImage = self.createImage(.red, size: CGSize.init(width: 20, height: 20))
let clearImage = self.createImage(.yellow, size: CGSize.init(width: 20, height: 20))
let bookmarkImage = self.createImage(.blue, size: CGSize.init(width: 20, height: 20))
let resultsListImage = self.createImage(.orange, size: CGSize.init(width: 20, height: 20))

searchBar.setImage(searchImage, for: .search, state: .normal)
searchBar.setImage(clearImage, for: .clear, state: .normal)
searchBar.setImage(bookmarkImage, for: .bookmark, state: .normal)
searchBar.setImage(resultsListImage, for: .resultsList, state: .normal)
默認樣式 高亮輸入空白 高亮輸入內(nèi)容

搜索結果列表圖標在什么條件下會顯示呢荡灾?我沒有試出來。

15. 設置(獲人仓)搜索框的圖標的偏移量

除了可以設置(獲扰稀) 14 中的圖片,還可以設置(獲壬そ凇)的偏移量荧缘。

open func setPositionAdjustment(_ adjustment: UIOffset, for icon: UISearchBarIcon)

open func positionAdjustment(for icon: UISearchBarIcon) -> UIOffset

用例:

let searchBar = searchController.searchBar
searchBar.setPositionAdjustment(UIOffset.init(horizontal: 10, vertical: 10), for: .search)
默認樣式 高亮
16. 顯示(隱藏)取消按鈕

可以用以下方法設置顯示(隱藏)取消按鈕:

open func setShowsCancelButton(_ showsCancelButton: Bool, animated: Bool)

當我們希望徹底隱藏掉取消按鈕的時候,應該怎么做呢拦宣?經(jīng)過測試發(fā)現(xiàn)截粗,只有在 UISearchControllerdelegate 中的 didPresentSearchController(_) 實現(xiàn)內(nèi)調用可以實現(xiàn)隱藏取消按鈕。

extension ViewController: UISearchControllerDelegate {
    func didPresentSearchController(_ searchController: UISearchController) {
        searchController.searchBar.setShowsCancelButton(false, animated: false)
    }
}

效果如下:


可以發(fā)現(xiàn)取消按鈕先顯示了一下鸵隧,然后隱藏了绸罗,效果并不理想。如果想徹底隱藏取消按鈕豆瘫,有一種方法是繼承 UISearchControllerUISearchBar 實現(xiàn)自定義珊蟀。代碼如下:

// 自定義 UISearchBar 
class CustomSearchBar: UISearchBar {
    override func layoutSubviews() {
        super.layoutSubviews()
        setShowsCancelButton(false, animated: false)
    }
}

// 自定義 UISearchController
class CustomSearchController: UISearchController {

    lazy var _searchBar: CustomSearchBar = { [unowned self] in
        let result = CustomSearchBar(frame: CGRect.zero)
        result.delegate = self
        return result
    }()
    
    override var searchBar: UISearchBar {
        return _searchBar
    }
}

extension CustomSearchController: UISearchBarDelegate {
    
}

使用自定義的 CustomSearchController 可以完全隱藏取消按鈕,效果如下:

17. 設置取消按鈕的名稱

可以通過以下幾個方法修改取消按鈕的名稱:

方法一:

let searchBar = searchController.searchBar
searchBar.setValue("Done", forKey:"_cancelButtonText")

方法二:

UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).title = "Done"

方法三:

let searchBar = searchController.searchBar
searchBar.showsCancelButton = true
let cancelButton = searchBar.value(forKey: "cancelButton") as? UIButton
cancelButton?.setTitle("Done", for: .normal)

注意方法三的設置順序外驱,需要先設置 showsCancelButton 為 true育灸,這種方式的問題在于 cancelButton 一開始就要被設置為顯示腻窒。


18. 搜索框附屬分欄條

在搜索框下面可以顯示搜索框附屬分欄條
用例:

let searchBar = searchController.searchBar
searchBar.showsScopeBar = true
// 選擇按鈕視圖的按鈕標題
searchBar.scopeButtonTitles = ["One", "Two", "Three"]
// 選中的選擇按鈕下標值磅崭,默認值為 0定页,如果超出索引范圍則會被忽略
searchBar.selectedScopeButtonIndex = 1
默認樣式 高亮
19. 搜索框附屬分欄條——背景顏色

可以通過通過 scopeBarBackgroundImage 設置搜索框附屬分欄條的背景顏色

open var scopeBarBackgroundImage: UIImage?

用例(注意以下代碼的順序可能會產(chǎn)生不同的效果):

let searchBar = searchController.searchBar
searchBar.showsScopeBar = true
// 選擇按鈕視圖的按鈕標題
searchBar.scopeButtonTitles = ["One", "Two", "Three"]
// 選中的選擇按鈕下標值,默認值為 0绽诚,如果超出索引范圍則會被忽略
searchBar.selectedScopeButtonIndex = 1
searchBar.scopeBarBackgroundImage = self.createImage(UIColor.yellow, size: CGSize.init(width: 200, height: 100))
默認樣式 高亮
20. 搜索框附屬分欄條——按鈕的背景圖片

用以下方法可以設置(獲取)搜索框附屬分欄條按鈕的背景圖片:

open func setScopeBarButtonBackgroundImage(_ backgroundImage: UIImage?, for state: UIControlState)

open func scopeBarButtonBackgroundImage(for state: UIControlState) -> UIImage?

用例:

let searchBar = searchController.searchBar
searchBar.showsScopeBar = true
// 選擇按鈕視圖的按鈕標題
searchBar.scopeButtonTitles = ["One", "Two", "Three"]
// 選中的選擇按鈕下標值杭煎,默認值為 0恩够,如果超出索引范圍則會被忽略
searchBar.selectedScopeButtonIndex = 1
searchBar.scopeBarBackgroundImage = self.createImage(UIColor.yellow, size: CGSize.init(width: 200, height: 100))
searchBar.setScopeBarButtonBackgroundImage(createImage(.orange, size: CGSize.init(width: 20, height: 20)), for: .normal)
默認樣式 高亮
21. 搜索框附屬分欄條——按鈕的分割線圖片

可以用以下方法設置(獲取)搜索框附屬分欄條按鈕的分割線圖片:

open func setScopeBarButtonDividerImage(_ dividerImage: UIImage?, forLeftSegmentState leftState: UIControlState, rightSegmentState rightState: UIControlState)

open func scopeBarButtonDividerImage(forLeftSegmentState leftState: UIControlState, rightSegmentState rightState: UIControlState) -> UIImage?

用例:

let searchBar = searchController.searchBar
searchBar.showsScopeBar = true
// 選擇按鈕視圖的按鈕標題
searchBar.scopeButtonTitles = ["One", "Two", "Three"]
// 選中的選擇按鈕下標值羡铲,默認值為 0蜂桶,如果超出索引范圍則會被忽略
searchBar.selectedScopeButtonIndex = 1
searchBar.setScopeBarButtonDividerImage(createImage(.red, size: CGSize.init(width: 10, height: 20)), forLeftSegmentState: .normal, rightSegmentState: .normal)
默認樣式 高亮
22. 搜索框附屬分欄條——按鈕的標題樣式

可以用以下方法設置(獲取)搜索框附屬分欄條按鈕的標題樣式:

open func setScopeBarButtonTitleTextAttributes(_ attributes: [String : Any]?, for state: UIControlState)

open func scopeBarButtonTitleTextAttributes(for state: UIControlState) -> [String : Any]?

用例:

let searchBar = searchController.searchBar
searchBar.showsScopeBar = true
// 選擇按鈕視圖的按鈕標題
searchBar.scopeButtonTitles = ["One", "Two", "Three"]
// 選中的選擇按鈕下標值也切,默認值為 0扑媚,如果超出索引范圍則會被忽略
searchBar.selectedScopeButtonIndex = 1
searchBar.setScopeBarButtonTitleTextAttributes([NSAttributedStringKey.font.rawValue : UIFont.systemFont(ofSize: 20), NSAttributedStringKey.foregroundColor.rawValue : UIColor.red], for: .normal)
searchBar.setScopeBarButtonTitleTextAttributes([NSAttributedStringKey.font.rawValue : UIFont.systemFont(ofSize: 24), NSAttributedStringKey.foregroundColor.rawValue : UIColor.yellow], for: .selected)
默認樣式 高亮

23. 搜索頂部提示

在搜索框頂部可以通知 prompt 設置提示信息。

比如:

let searchBar = searchController.searchBar
searchBar.prompt = "非活躍"

可以在 searchBar 的代理里修改 prompt 的內(nèi)容雷恃,例如:

extension ViewController: UISearchBarDelegate {
    func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
        searchBar.prompt = "開始編輯"
    }
    
    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
        searchBar.prompt = "取消編輯"
    }
    
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        searchBar.prompt = "當前輸入:\(searchText)"
    }
    
    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
        searchBar.prompt = "點擊取消"
    }
}

效果如下

非活躍 開始編輯 輸入內(nèi) 取消編輯

可以發(fā)現(xiàn)頂部的提示文字和輸入框重合了疆股。所以向下調整一下輸入框的偏移量。
prompt 為空時 searchBar 的高度為 56倒槐,不為空時 searchBar 的高度為 75旬痹,所以我們將輸入框向下調整 19:

searchBar.searchFieldBackgroundPositionAdjustment = UIOffset.init(horizontal: 0, vertical: 19)

效果如下

非活躍 開始編輯 輸入內(nèi) 取消編輯

可以發(fā)現(xiàn)還是有問題:

  1. 取消按鈕和輸入框不在一行上了
  2. 如果 prompt 有時有值,有時為空讨越,searchBar 的高度無法靈活改變两残。

這些問題暫時沒有找到解決方案。

其他待解決問題
  1. isTranslucent 沒有發(fā)現(xiàn)效果
  2. inputAssistantItem
  3. inputAccessoryView
  4. 搜索結果列表圖標在什么條件下會顯示

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末把跨,一起剝皮案震驚了整個濱河市人弓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌着逐,老刑警劉巖崔赌,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異滨嘱,居然都是意外死亡峰鄙,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門太雨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吟榴,“玉大人,你說我怎么就攤上這事囊扳》苑” “怎么了兜看?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長狭瞎。 經(jīng)常有香客問我细移,道長,這世上最難降的妖魔是什么熊锭? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任弧轧,我火速辦了婚禮,結果婚禮上碗殷,老公的妹妹穿的比我還像新娘精绎。我一直安慰自己,他們只是感情好锌妻,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布代乃。 她就那樣靜靜地躺著,像睡著了一般仿粹。 火紅的嫁衣襯著肌膚如雪搁吓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天吭历,我揣著相機與錄音堕仔,去河邊找鬼。 笑死晌区,一個胖子當著我的面吹牛贮预,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播契讲,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼仿吞,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了捡偏?” 一聲冷哼從身側響起唤冈,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎银伟,沒想到半個月后你虹,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡彤避,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年傅物,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片琉预。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡董饰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情卒暂,我是刑警寧澤啄栓,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站也祠,受9級特大地震影響昙楚,放射性物質發(fā)生泄漏。R本人自食惡果不足惜诈嘿,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一堪旧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧奖亚,春花似錦崎场、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽干厚。三九已至李滴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蛮瞄,已是汗流浹背所坯。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留挂捅,地道東北人芹助。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像闲先,于是被迫代替她去往敵國和親状土。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容