UIKit框架(三十九) —— iOS 13中UISearchController 和 UISearchBar的新更改(一)

版本記錄

版本號 時(shí)間
V1.0 2020.05.05 星期二

前言

iOS中有關(guān)視圖控件用戶能看到的都在UIKit框架里面演训,用戶交互也是通過UIKit進(jìn)行的。感興趣的參考上面幾篇文章拂募。
1. UIKit框架(一) —— UIKit動(dòng)力學(xué)和移動(dòng)效果(一)
2. UIKit框架(二) —— UIKit動(dòng)力學(xué)和移動(dòng)效果(二)
3. UIKit框架(三) —— UICollectionViewCell的擴(kuò)張效果的實(shí)現(xiàn)(一)
4. UIKit框架(四) —— UICollectionViewCell的擴(kuò)張效果的實(shí)現(xiàn)(二)
5. UIKit框架(五) —— 自定義控件:可重復(fù)使用的滑塊(一)
6. UIKit框架(六) —— 自定義控件:可重復(fù)使用的滑塊(二)
7. UIKit框架(七) —— 動(dòng)態(tài)尺寸UITableViewCell的實(shí)現(xiàn)(一)
8. UIKit框架(八) —— 動(dòng)態(tài)尺寸UITableViewCell的實(shí)現(xiàn)(二)
9. UIKit框架(九) —— UICollectionView的數(shù)據(jù)異步預(yù)加載(一)
10. UIKit框架(十) —— UICollectionView的數(shù)據(jù)異步預(yù)加載(二)
11. UIKit框架(十一) —— UICollectionView的重用陈症、選擇和重排序(一)
12. UIKit框架(十二) —— UICollectionView的重用录肯、選擇和重排序(二)
13. UIKit框架(十三) —— 如何創(chuàng)建自己的側(cè)滑式面板導(dǎo)航(一)
14. UIKit框架(十四) —— 如何創(chuàng)建自己的側(cè)滑式面板導(dǎo)航(二)
15. UIKit框架(十五) —— 基于自定義UICollectionViewLayout布局的簡單示例(一)
16. UIKit框架(十六) —— 基于自定義UICollectionViewLayout布局的簡單示例(二)
17. UIKit框架(十七) —— 基于自定義UICollectionViewLayout布局的簡單示例(三)
18. UIKit框架(十八) —— 基于CALayer屬性的一種3D邊欄動(dòng)畫的實(shí)現(xiàn)(一)
19. UIKit框架(十九) —— 基于CALayer屬性的一種3D邊欄動(dòng)畫的實(shí)現(xiàn)(二)
20. UIKit框架(二十) —— 基于UILabel跑馬燈類似效果的實(shí)現(xiàn)(一)
21. UIKit框架(二十一) —— UIStackView的使用(一)
22. UIKit框架(二十二) —— 基于UIPresentationController的自定義viewController的轉(zhuǎn)場和展示(一)
23. UIKit框架(二十三) —— 基于UIPresentationController的自定義viewController的轉(zhuǎn)場和展示(二)
24. UIKit框架(二十四) —— 基于UICollectionViews和Drag-Drop在兩個(gè)APP間的使用示例 (一)
25. UIKit框架(二十五) —— 基于UICollectionViews和Drag-Drop在兩個(gè)APP間的使用示例 (二)
26. UIKit框架(二十六) —— UICollectionView的自定義布局 (一)
27. UIKit框架(二十七) —— UICollectionView的自定義布局 (二)
28. UIKit框架(二十八) —— 一個(gè)UISplitViewController的簡單實(shí)用示例 (一)
29. UIKit框架(二十九) —— 一個(gè)UISplitViewController的簡單實(shí)用示例 (二)
30. UIKit框架(三十) —— 基于UICollectionViewCompositionalLayout API的UICollectionViews布局的簡單示例(一)
31. UIKit框架(三十一) —— 基于UICollectionViewCompositionalLayout API的UICollectionViews布局的簡單示例(二)
32. UIKit框架(三十二) —— 替換Peek and Pop交互的基于iOS13的Context Menus(一)
33. UIKit框架(三十三) —— 替換Peek and Pop交互的基于iOS13的Context Menus(二)
34. UIKit框架(三十四) —— Accessibility的使用(一)
35. UIKit框架(三十五) —— Accessibility的使用(二)
36. UIKit框架(三十六) —— UICollectionView UICollectionViewDiffableDataSource的使用(一)
37. UIKit框架(三十七) —— UICollectionView UICollectionViewDiffableDataSource的使用(二)
38. UIKit框架(三十八) —— 基于CollectionView轉(zhuǎn)盤效果的實(shí)現(xiàn)(一)

開始

首先看下主要內(nèi)容:

在本UISearchController教程中,您將了解UISearchToken试伙、UISearchTextFieldiOS 13中引入的其他新api嘁信。來自翻譯于样。

下面看下寫作環(huán)境

Swift 5, iOS 13, Xcode 11

接著就是正文了疏叨。

UISearchBarUISearchController是iOS應(yīng)用開發(fā)的主要部分。不過穿剖,雖然UISearchBariOS 2引入以來一直在周期性地變化蚤蔓,但自從蘋果在iOS 8中引入它以來,UISearchController就一直是相當(dāng)穩(wěn)定的糊余。在iOS 13中,蘋果對兩者都進(jìn)行了更新宣决。

蘋果還推出了UISearchToken尊沸,為UISearchController提供了急需的能力洼专。只需很少的努力,您就可以讓用戶執(zhí)行復(fù)雜的搜索查詢蜡镶,以及他們習(xí)慣的基于文本的搜索帽哑。

如果您曾經(jīng)編寫過冗長妻枕、脆弱的代碼來遍歷搜索欄的視圖層次結(jié)構(gòu)以獲得對搜索text field的引用屡谐,那么這里有更多的好消息愕掏。UISearchTextField現(xiàn)在作為一個(gè)屬性公開,這使得定制更加容易滑潘。

在本教程中,您將學(xué)習(xí):

  • 如何控制搜索結(jié)果控制器的顯示钮孵。
  • 關(guān)于搜索令牌(search tokens)的所有信息诅需。
  • 如何創(chuàng)建和使用搜索令牌蔫仙。
  • 如何自定義UISearchControllersearch bar 和它的text field丑慎。

在本教程中腻异,您將在L.I.S.T.E.D中進(jìn)行學(xué)習(xí),它是Large International Sorted Tally of Earth DwellersL.I.S.T.E.D.是一個(gè)跟蹤世界人口總數(shù)的組織罐旗。他們目前有2018年和2019年所有國家的人口。

預(yù)計(jì)到2020年人口數(shù)據(jù)的發(fā)布,他們希望擴(kuò)大搜索能力娇豫。作為一個(gè)地球居民,你將幫助重構(gòu)應(yīng)用程序,并將其搜索功能提升到一個(gè)全新的組織層面。

首先在starter文件夾中打開列表LISTED.xcodeproj中夹供,然后打開Main.storyboard

你會(huì)發(fā)現(xiàn)這個(gè)應(yīng)用程序非常簡單。只有兩個(gè)視圖控制器,它們被封裝在一個(gè)導(dǎo)航控制器中蒿秦。

構(gòu)建和運(yùn)行。你會(huì)看到:

現(xiàn)在祟辟,搜索“new”。你會(huì)看到這些搜索結(jié)果:

結(jié)果顯示所有年份的匹配馍悟。在范圍欄中點(diǎn)擊2018或2019將縮小搜索范圍∫阏現(xiàn)在就試試2019年戏蔑,你會(huì)看到:

很好捍壤,基本的搜索工作得很好。現(xiàn)在寡夹,你需要進(jìn)一步優(yōu)化!


Using the Search Results Controller

UISearchController為顯示結(jié)果提供了兩個(gè)選項(xiàng):在顯示原始數(shù)據(jù)的相同視圖中顯示結(jié)果,或者使用搜索結(jié)果控制器法牲。

L.I.S.T.E.D.使用搜索結(jié)果控制器(search results controller)以與主控制器稍微不同的格式顯示結(jié)果。當(dāng)用戶點(diǎn)擊搜索欄時(shí),主視圖控制器仍然可見。結(jié)果視圖控制器在用戶開始輸入搜索后顯示。

iOS 13之前,你幾乎無法控制這種行為零蓉,但現(xiàn)在你可以在UISearchController中使用新添加的showsSearchResultsController來定制你的結(jié)果章喉。在下一節(jié)中您將看到如何實(shí)現(xiàn)部蛇。

1. Displaying Results: You’re in Control

要控制何時(shí)顯示搜索結(jié)果抹腿,您需要對搜索欄中的更改做出反應(yīng)房蝉。為了讓它工作檀蹋,主視圖控制器將遵循UISearchResultsUpdating

當(dāng)搜索欄成為第一個(gè)響應(yīng)器或文本發(fā)生更改時(shí),委托接收updateSearchResults(for:)調(diào)用。您將使用它來觸發(fā)結(jié)果控制器的顯示。

打開MainViewController.swift,并在UISearchBarDelegate之后添加以下內(nèi)容:

// MARK: -

extension MainViewController: UISearchResultsUpdating {
  func updateSearchResults(for searchController: UISearchController) {
    searchController.showsSearchResultsController = true
  }
}

搜索欄成為第一個(gè)響應(yīng)者時(shí),搜索結(jié)果現(xiàn)在顯示岂却。

在進(jìn)行測試之前,添加以下代碼作為viewDidLoad()中的最后一行:

searchController.searchResultsUpdater = self

search results updater負(fù)責(zé)更新搜索結(jié)果控制器(search results controller)正驻。這里,您將該職責(zé)分配給主控制器。

構(gòu)建和運(yùn)行。點(diǎn)擊搜索欄,你會(huì)看到一個(gè)空的搜索結(jié)果控制器打肝。

你現(xiàn)在可以完全控制搜索結(jié)果的顯示和隱藏。正如您現(xiàn)在所感受到的那樣強(qiáng)大鉴嗤,顯示一個(gè)空白的結(jié)果控制器并不是一個(gè)很好的用戶體驗(yàn)。您將很快解決這個(gè)問題经柴,但是首先牛哺,您需要了解關(guān)于搜索令牌(search tokens)的更多信息椰拒。


Everything You Need to Know About Search Tokens

搜索令牌(Search token)可以說是蘋果在ios13中添加的最有趣的搜索功能便瑟。如果你在iOS 13上使用蘋果的Mail or Photo應(yīng)用程序浇雹,你可能已經(jīng)看到了搜索令牌的作用。

Mail應(yīng)用程序使用搜索令牌來創(chuàng)建復(fù)雜的搜索。點(diǎn)擊搜索欄會(huì)顯示unread messagesflagged messages等建議。

Tokens可以表示復(fù)雜的搜索敌完,比如通過地理位置進(jìn)行搜索,或者使用預(yù)先確定的文本進(jìn)行簡單的搜索得哆。搜索令牌的鍵在UISearchToken中是representedObject

representedObject是一個(gè)Any?可以包含對您有用的任何類型的數(shù)據(jù)。

一定要記住壹无,representedObject是強(qiáng)引用的岖是。它所引用的任何對象都可能在周圍停留相當(dāng)長的一段時(shí)間前硫。使用輕量級數(shù)據(jù)來避免問題。String、intNSManagedObjectID都是不錯(cuò)的選擇偷线。

1. Creating Tokens

現(xiàn)在是處理單擊搜索欄時(shí)看到的空搜索結(jié)果視圖的時(shí)候了亥曹。這是顯示用戶可用令牌列表的好地方。

打開ResultsTableViewController.swift熊响。在類的頂部铭若,countries之后嫂侍,添加以下內(nèi)容:

var searchTokens: [UISearchToken] = []

這里各淀,您正在創(chuàng)建一個(gè)數(shù)組來保存搜索標(biāo)記南捂。在這一行之后,添加以下內(nèi)容:

var isFilteringByCountry: Bool {
  return countries != nil
}

當(dāng)用戶進(jìn)行搜索時(shí)吱晒,這個(gè)計(jì)算得到的布爾值將返回true驼壶;當(dāng)用戶不進(jìn)行搜索時(shí)纪铺,將返回false烹棉。你很快就會(huì)用到它。

在文件末尾的類下面摘昌,添加以下擴(kuò)展名:

// MARK: -

extension ResultsTableViewController {
  func makeTokens() {
    // 1
    let continents = Continent.allCases
    searchTokens = continents.map { (continent) -> UISearchToken in
      // 2
      let globeImage = UIImage(systemName: "globe")
      let token = UISearchToken(icon: globeImage, text: continent.description)
      // 3
      token.representedObject = Continent(rawValue: continent.description)
      // 4
      return token
    }
  }
}

這些代碼的內(nèi)容如下:

  • 1) 創(chuàng)建一個(gè)所有continents的數(shù)組喉镰。
  • 2) 創(chuàng)建表示token的圖像。接下來柱蟀,使用圖像和當(dāng)前continents的描述,創(chuàng)建一個(gè)search token痰哨。
  • 3) 將continents的描述賦給tokenrepresentedObject。稍后您將使用它來將搜索范圍縮小到特定的continents撬讽。使用輕量級值(如字符串)非常適合這種情況。
  • 4) 返回token尝蠕,它附加到您先前創(chuàng)建的searchTokens烘豌。

viewDidLoad()中廊佩,添加這一行作為最后一行:

makeTokens()

在這里,您將在視圖加載時(shí)創(chuàng)建search token。就是這樣!創(chuàng)建search token就是這么簡單。

在重新構(gòu)建和運(yùn)行之前扇住,您需要更新結(jié)果控制器來顯示這些新token。你將在下一步中做庸汗。

2. Making a UI for Selecting Tokens

現(xiàn)在,您將創(chuàng)建一個(gè)UI立宜,以使用Mail應(yīng)用程序作為靈感來選擇token。首先鸦采,將tableView(_:numberOfRowsInSection:)替換為:

override func tableView(
  _ tableView: UITableView,
  numberOfRowsInSection section: Int
) -> Int {
  return isFilteringByCountry ? (countries?.count ?? 0) : searchTokens.count
}

使用前面創(chuàng)建的isFilteringByCountry,您可以確定是使用search tokens計(jì)數(shù)還是使用countries計(jì)數(shù)來設(shè)置表視圖中的行數(shù)。如果用戶正在搜索膛檀,則發(fā)送國家計(jì)數(shù)(如果countriesnil,則發(fā)送零)挺尾。當(dāng)它們不進(jìn)行搜索時(shí)赦抖,您發(fā)送token count蚕键。

接下來兽赁,用以下代碼替換tableView(_:cellForRowAt:)

override func tableView(
  _ tableView: UITableView,
  cellForRowAt indexPath: IndexPath
) -> UITableViewCell {
  // 1
  if
    isFilteringByCountry,
    let cell = tableView.dequeueReusableCell(
      withIdentifier: "results",
      for: indexPath) as? CountryCell {
    cell.country = countries?[indexPath.row]
    return cell
  
  // 2
  } else if
    let cell = tableView.dequeueReusableCell(
      withIdentifier: "search",
      for: indexPath) as? SearchTokenCell {
    cell.token = searchTokens[indexPath.row]
    return cell
  }

  // 3
  return UITableViewCell()
}

你可以這樣處理這些代碼:

  • 1) 首先檢查用戶是否正在搜索某個(gè)國家。如果是枕赵,則使用CountryCell其掂。然后將國家分配給單元格的國家并返回單元格叹谁。
  • 2) 否則,使用SearchTokenCell。將token分配給celltoken并返回cell夭拌。
  • 3) 如果所有操作都失敗,則返回一個(gè)UITableViewCell噩凹。

構(gòu)建和運(yùn)行。點(diǎn)擊搜索欄,但不要輸入任何文本。您將看到為選擇search token而創(chuàng)建的UI优构。

這是一個(gè)非常棒的方法,但是有一個(gè)問題:如果您點(diǎn)擊其中一個(gè)token劳澄,什么也不會(huì)發(fā)生。噓蔚万!別擔(dān)心,你下次會(huì)修好的肖方。

3. Adding Tokens to the Search Bar

當(dāng)您在結(jié)果視圖中點(diǎn)擊一個(gè)token entries時(shí)司草,什么也不會(huì)發(fā)生柬讨。應(yīng)該發(fā)生的是將token添加到搜索欄中境输。這向用戶表明他們正在搜索他們指定的大陸。

results controller不能添加token姑丑,因?yàn)樗皇撬阉鳈诘乃姓哒ぐА.?dāng)用戶點(diǎn)擊一個(gè)token時(shí)戳晌,你必須通知主視圖控制器泼菌。為此嘉蕾,您將使用委托協(xié)議以清。

在類之前障贸,將以下代碼添加到ResultsTableViewController.swift的頂部:

protocol ResultsTableViewDelegate: class {
  func didSelect(token: UISearchToken)
}

在類的頂部戳杀,在isFilteringByCountry之后咐低,添加以下內(nèi)容:

weak var delegate: ResultsTableViewDelegate?

您已經(jīng)創(chuàng)建了一個(gè)簡單的協(xié)議揽思,當(dāng)用戶點(diǎn)擊一個(gè)token時(shí),您將使用它來通知委托≡ㄐ現(xiàn)在绰更,在tableView(_:cellForRowAt:)之后添加以下代碼:

override func tableView(
  _ tableView: UITableView,
  didSelectRowAt indexPath: IndexPath
) {
  guard !isFilteringByCountry else { return }
  delegate?.didSelect(token: searchTokens[indexPath.row])
}

首先,檢查視圖是否顯示tokens or countries锡宋。如果是一個(gè)國家儡湾,則忽略行選擇。否則执俩,您將通知委托用戶所點(diǎn)擊的search token徐钠。

MainViewController.swift,在文件底部添加如下內(nèi)容:

// MARK: -

extension MainViewController: ResultsTableViewDelegate {
  func didSelect(token: UISearchToken) {
    // 1
    let searchTextField = searchController.searchBar.searchTextField
    // 2
    searchTextField.insertToken(token, at: searchTextField.tokens.count)
    // 3
    searchFor(searchController.searchBar.text)
  }
}

當(dāng)通知主視圖控制器時(shí)役首,用戶已經(jīng)選擇了一個(gè)token尝丐,你:

  • 1) 獲取搜索欄的text field
  • 2) 使用fieldinsertToken(_:at:)token添加到已經(jīng)在field中的tokens的末尾衡奥。
  • 3) 運(yùn)行搜索算法爹袁。

viewDidLoad()中,在resultsTableViewController實(shí)例化之后矮固,添加:

resultsTableViewController.delegate = self

現(xiàn)在失息,主視圖控制器將是結(jié)果控制器的代理。

構(gòu)建并運(yùn)行档址,然后點(diǎn)擊搜索欄盹兢。當(dāng)結(jié)果控制器出現(xiàn)時(shí),點(diǎn)擊“Search by Europe”守伸。然后绎秒,輸入“united”,你會(huì)看到:

令人興奮尼摹!您已經(jīng)向搜索欄添加了一個(gè)search token见芹。然而,它似乎不起作用蠢涝。

除非地理環(huán)境從你上高中起就發(fā)生了變化玄呛,否則美國和阿拉伯聯(lián)合酋長國不會(huì)出現(xiàn)在歐洲。

問題出在搜索算法上:您沒有更新它以使其考慮到tokens惠赫。解決這個(gè)問題是你的下一個(gè)挑戰(zhàn)。


Modifying Your Search to Use Tokens

當(dāng)前的搜索算法使用搜索欄的文本和范圍來執(zhí)行搜索故黑。您還將重構(gòu)它以使用tokens儿咱。

在此之前庭砍,您需要?jiǎng)?chuàng)建兩個(gè)helper屬性。在MainViewController.swift中混埠,在resultsTableViewController之后添加以下內(nèi)容:

var searchContinents: [String] {
  // 1
  let tokens = searchController.searchBar.searchTextField.tokens
  // 2
  return tokens.compactMap {
    ($0.representedObject as? Continent)?.description
  }
}

該計(jì)算屬性將:

  • 1) 創(chuàng)建在搜索欄的text field中包含的tokens數(shù)組怠缸。
  • 2) 使用每個(gè)tokenrepresentedObject返回大陸字符串?dāng)?shù)組。

searchContinents之后钳宪,添加代碼:

var isSearchingByTokens: Bool {
  return
    searchController.isActive &&
    searchController.searchBar.searchTextField.tokens.count > 0
}

如果搜索控制器處于活動(dòng)狀態(tài)揭北,并且搜索欄包含搜索token,則此屬性返回true吏颖。

使用這些新屬性搔体,將searchFor(_:)替換為:

func searchFor(_ searchText: String?) {
  // 1
  guard searchController.isActive else { return }
  // 2
  guard let searchText = searchText else {
    resultsTableViewController.countries = nil
    return
  }
  // 3
  let selectedYear = selectedScopeYear()
  let allCountries = countries.values.joined()
  let filteredCountries = allCountries.filter { (country: Country) -> Bool in
    // 4
    let isMatchingYear = selectedYear == Year.all.description ? 
      true : (country.year.description == selectedYear)
    // 5
    let isMatchingTokens = searchContinents.count == 0 ? 
      true : searchContinents.contains(country.continent.description)
    // 6
    if !searchText.isEmpty {
      return
        isMatchingYear &&
        isMatchingTokens &&
        country.name.lowercased().contains(searchText.lowercased())
    // 7
    } else if isSearchingByTokens {
      return isMatchingYear && isMatchingTokens
    }
    // 8
    return false
  }
  // 9
  resultsTableViewController.countries = 
    filteredCountries.count > 0 ? filteredCountries : nil
}

新的搜索算法做以下工作:

  • 1) 如果搜索控制器(search controller)當(dāng)前不是活動(dòng)的,它將終止半醉。
  • 2) 如果搜索文本為nil疚俱,則將結(jié)果控制器的countries設(shè)置為nil并終止。
  • 3) 從范圍欄中獲取選定的年份缩多。接下來呆奕,創(chuàng)建一個(gè)所有國家的數(shù)組并開始過濾該數(shù)組。
  • 4) 國家每年出現(xiàn)一次衬吆。根據(jù)2018年和2019年的數(shù)據(jù)梁钾,每個(gè)國家都被列出了兩次。過濾時(shí)的第一步是創(chuàng)建一個(gè)布爾值逊抡,如果選擇的年份是“all”姆泻,則為true。如果不是秦忿,則返回一個(gè)布爾值麦射,該布爾值基于該國的年份是否等于所選年份。
  • 5) 使用之前創(chuàng)建的searchContinents灯谣,如果國家的大陸匹配任何選定的tokens潜秋,就創(chuàng)建一個(gè)布爾值。如果searchContinentsnil胎许,則返回true峻呛,因?yàn)?code>nil表示匹配所有大陸。
  • 6) 如果有任何搜索文本辜窑,如果年份匹配钩述,令牌匹配,并且國家名稱包含搜索文本中的任何字符穆碎,那么您將返回國家牙勘。
  • 7) 如果您有token但沒有文本,則返回與年份和token所在大陸匹配的國家。
  • 8) 當(dāng)這兩種情況都不為true時(shí)方面,您將返回false放钦。
  • 9) 將任何經(jīng)過篩選的國家分配給結(jié)果控制器的countries。如果沒有恭金,賦值為nil操禀。

構(gòu)建和運(yùn)行。點(diǎn)擊搜索欄横腿,像上次一樣颓屑,點(diǎn)擊Search by Europe,然后輸入united耿焊。你只會(huì)看到英國2018年和2019年的entries揪惦。

雖然這很神奇,但現(xiàn)在還不要慶祝搀别。確保您所做的更改沒有影響到在沒有tokens的情況下進(jìn)行搜索的能力丹擎。

在搜索text field中選擇Europe token并刪除它,但不刪除單詞“united”歇父。你會(huì)看到:

哇蒂培!你做了一些偉大的工作。只有一些小的改變榜苫,你已經(jīng)徹底改變了L.I.S.T.E.D.的搜索功能护戳。


Hiding the Scope Bar

在您可以將其稱為準(zhǔn)備好投入生產(chǎn)之前,您還有一些事情要做垂睬。L.I.S.T.E.D.設(shè)計(jì)團(tuán)隊(duì)已經(jīng)確定媳荒,當(dāng)結(jié)果控制器顯示token selection UI時(shí),scope bar不應(yīng)該是可見的驹饺。

要實(shí)現(xiàn)這一點(diǎn)钳枕,請轉(zhuǎn)到viewDidLoad()并將其添加為最后一行:

searchController.automaticallyShowsScopeBar = false

ios13之前,scope bar總是會(huì)自動(dòng)顯示∩鸵迹現(xiàn)在鱼炒,您可以通過使用新的1automaticallyShowsScopeBar1來控制這種行為。

注意:有一個(gè)類似的automaticallyShowsCancelButton蝌借。此屬性允許您控制搜索欄的“取消”按鈕的可見性昔瞧。雖然在這個(gè)項(xiàng)目中不需要它,但是應(yīng)該知道它的存在菩佑。

接下來自晰,找到selectedScopeYear()并在其后面添加以下內(nèi)容:

func showScopeBar(_ show: Bool) {
  guard searchController.searchBar.showsScopeBar != show else { return }
  searchController.searchBar.setShowsScope(show, animated: true)
  view.setNeedsLayout()
}

在這里,檢查搜索欄的showsScopeBar是否匹配show稍坯。如果是這樣酬荞,你就會(huì)停下來,因?yàn)槟銦o事可做。

如果不匹配混巧,則使用新的setShowsScope(_:animated:)來顯示或隱藏scope bar糟把。

最后,必須在視圖控制器的視圖上調(diào)用setNeedsLayout()牲剃。

現(xiàn)在,您將使用這個(gè)新函數(shù)來顯示和隱藏scope bar雄可。在UISearchBarDelegate中凿傅,找到searchBar(_:textDidChange:)并添加以下內(nèi)容作為最后一行:

let showScope = !searchText.isEmpty
showScopeBar(showScope)

如果搜索文本不是空的,應(yīng)該顯示scope bar数苫。

searchBarCancelButtonClicked(_:)中聪舒,添加以下內(nèi)容作為最后一行:

showScopeBar(false)

現(xiàn)在,當(dāng)用戶點(diǎn)擊搜索欄的取消按鈕時(shí)虐急,您將隱藏scope bar箱残。

最后,在ResultsTableViewDelegate中止吁,在didSelect(token:)結(jié)尾添加以下內(nèi)容:

showScopeBar(true)

當(dāng)用戶選擇一個(gè)token時(shí)被辑,您現(xiàn)在將顯示scope bar

構(gòu)建并運(yùn)行敬惦,然后點(diǎn)擊搜索欄盼理。您將不再看到scope bar

點(diǎn)擊一個(gè)token俄删,scope bar就會(huì)出現(xiàn)宏怔。


Customizing the Search Bar and Text Field

最后的任務(wù)是在搜索欄中添加一個(gè)主題。在ios13中顯示search text field之前畴椰,自定義field充滿了問題‰铮現(xiàn)在,隨著text field的暴露斜脂,您可以像定制任何其他UITextField一樣定制它抓艳。

1. Changing Text and Background Color

設(shè)計(jì)團(tuán)隊(duì)希望text field更突出一些,所以您的第一個(gè)任務(wù)是更改文本的顏色秽褒。

viewDidLoad()中壶硅,添加這一行作為最后一行:

searchController.searchBar.searchTextField.textColor = .rwGreen()

該項(xiàng)目有一個(gè)UIColor擴(kuò)展。這個(gè)擴(kuò)展返回一個(gè)非常特殊的綠色销斟,您最喜歡的教程站點(diǎn)使用它庐椒。在這里。您正在將search text field的文本顏色設(shè)置為華麗的綠色陰影蚂踊。

下一步是改變背景顏色约谈。當(dāng)search bar成為第一個(gè)響應(yīng)時(shí),它應(yīng)該變成透明的綠色。當(dāng)用戶取消搜索時(shí)棱诱,它應(yīng)該返回到默認(rèn)顏色泼橘。

要實(shí)現(xiàn)這一點(diǎn),在UISearchResultsUpdating擴(kuò)展中找到updateSearchResults(for:)迈勋,并將它替換為:

func updateSearchResults(for searchController: UISearchController) {
  // 1
  if searchController.searchBar.searchTextField.isFirstResponder {
    searchController.showsSearchResultsController = true
    // 2
    searchController.searchBar
      .searchTextField.backgroundColor = UIColor.rwGreen().withAlphaComponent(0.1)
  } else {
    // 3
    searchController.searchBar.searchTextField.backgroundColor = nil
  }
}

在這里炬灭,你是:

  • 1) 如果search text field是第一個(gè)響應(yīng)者,則顯示結(jié)果控制器靡菇。
  • 2) 將search text field的背景顏色更改為rwGreen重归。使用alpha組件使顏色透明。
  • 3) 如果search text field不是第一個(gè)響應(yīng)者厦凤,則將背景顏色設(shè)置回默認(rèn)值鼻吮。

UISearchDelegate中,查找searchBarCancelButtonClicked(_:)并將其添加為最后一行:

searchController.searchBar.searchTextField.backgroundColor = nil

如果用戶取消搜索较鼓,則將text field的背景設(shè)置為默認(rèn)值椎木。

構(gòu)建和運(yùn)行。點(diǎn)擊搜索欄博烂,點(diǎn)擊Search by Africa香椎,輸入“faso”。您將看到以下內(nèi)容:

您現(xiàn)在已經(jīng)設(shè)置了搜索text field的文本和背景主題禽篱。事情看起來很尖銳究流!

但是歉秫,現(xiàn)在這個(gè)token看起來不太對耘婚〕豆蓿總會(huì)有辦法的,不是嗎肥照?別擔(dān)心脚仔,你下次會(huì)修好的。

2. Changing the Color of Tokens

Token有幾個(gè)主題選項(xiàng)舆绎。例如鲤脏,您可以像前面那樣設(shè)置Token的圖標(biāo)。你也可以改變背景顏色吕朵,這是你接下來要做的猎醇。

viewDidLoad()中,添加這一行作為最后一行:

searchController.searchBar.searchTextField.tokenBackgroundColor = .rwGreen()

這里努溃,您將tokens的默認(rèn)背景顏色設(shè)置為rwGreen硫嘶。

構(gòu)建和運(yùn)行。點(diǎn)擊search梧税,點(diǎn)擊Search by Oceania沦疾,你會(huì)看到這個(gè):

看那些綠色称近!它真的可以幫助你出色的新搜索功能脫穎而出。

看看這些很好的資源哮塞,以了解更多關(guān)于UISearchController

后記

本篇主要講述了iOS 13UISearchControllerUISearchBar的新更改,感興趣的給個(gè)贊或者關(guān)注~~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末忆畅,一起剝皮案震驚了整個(gè)濱河市衡未,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌家凯,老刑警劉巖眠屎,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異肆饶,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)岖常,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門驯镊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人竭鞍,你說我怎么就攤上這事板惑。” “怎么了偎快?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵冯乘,是天一觀的道長。 經(jīng)常有香客問我晒夹,道長裆馒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任丐怯,我火速辦了婚禮喷好,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘读跷。我一直安慰自己梗搅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布效览。 她就那樣靜靜地躺著无切,像睡著了一般。 火紅的嫁衣襯著肌膚如雪丐枉。 梳的紋絲不亂的頭發(fā)上哆键,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機(jī)與錄音瘦锹,去河邊找鬼洼哎。 笑死烫映,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的噩峦。 我是一名探鬼主播锭沟,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼识补!你這毒婦竟也來了族淮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤凭涂,失蹤者是張志新(化名)和其女友劉穎祝辣,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體切油,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蝙斜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了澎胡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片孕荠。...
    茶點(diǎn)故事閱讀 39,795評論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖攻谁,靈堂內(nèi)的尸體忽然破棺而出稚伍,到底是詐尸還是另有隱情,我是刑警寧澤戚宦,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布个曙,位于F島的核電站,受9級特大地震影響受楼,放射性物質(zhì)發(fā)生泄漏垦搬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一艳汽、第九天 我趴在偏房一處隱蔽的房頂上張望悼沿。 院中可真熱鬧,春花似錦骚灸、人聲如沸糟趾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽义郑。三九已至,卻和暖如春丈钙,著一層夾襖步出監(jiān)牢的瞬間非驮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工雏赦, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留劫笙,地道東北人芙扎。 一個(gè)月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像填大,于是被迫代替她去往敵國和親戒洼。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評論 2 354