iOS翻譯-如何自定義SearchBar

jopen 8年前發布 | 14K 次閱讀 iOS開發 移動開發

翻譯了一篇appcoda的文章,介紹如何自定義SearchBar的文章

原文鏈接: http://www.appcoda.com/custom-search-bar-tutorial/

app里面經常需要展示一些搜索的數據顯示到tableview上。不幸的是,大部分開發者使用原生的控件。在iOS8里,蘋果提供了一個特殊的控件 UISearchDisplayController 。這個控件結合了 UISeachBar ,很輕松的添加搜索的功能。不過,現在已經成為了歷史。

UISearchController 在iOS8里面已經取代了 UISearchDisplayController . 盡管這雖然改變,但是在IB里面沒有繼承可視化控件,它必須用代碼去初始化配置,不過非常簡單。

除了上面所說的,有一個有趣的關于tableview datasource搜索的地方。iOS提供了一個searchbar預設的外觀,這個bar適用于大多數情況。 然而,當UI需要高度自定義,這個searchbar看起來與我們的不是那么搭。在這種情況下,我們的searchbar必須適當的定制。

在這個教程里面,會展示 UISearchController 在iOS8里面是如何搜索和過濾數據的,使用默認的searchbar。

接著如何重寫默認的searchbar的外觀,實現自定義。所以我們設置了 UISearchController 和 UISearchBar 的子類,里面的代碼通俗易懂,并且控件非常通用,可以復用。

Demo App Overview

我們將實現下面兩個界面

第一張在 UISearchController 使用默認 searchbar 。第二張是自定義的searchbar.

首先下載工程的: Demo

加載和展示數據

首先加載 countries.txt 文件里面的數據,然后我們再通過列表的方式展示。

打開 ViewController.swift 文件,聲明下面的屬性

var dataArray = [String]()   //countries.txt文件里面的內容,tableview展示的數據

var filteredArray = [String]()//搜索匹配的內容

var shouldShowSearchResults = false //控制是否需要展示數據

加載tableView所需要的數據數據

 func loadListOfCountries() {
    // Specify the path to the countries list file.
    let pathToFile = NSBundle.mainBundle().pathForResource("countries", ofType: "txt")

    if let path = pathToFile {
        // Load the file contents as a string.
        let countriesString = String(contentsOfFile: path, encoding: NSUTF8StringEncoding, error: nil)!

        // Append the countries from the string to the dataArray array by breaking them using the line change character.
        dataArray = countriesString.componentsSeparatedByString("\n")

        // Reload the tableview.
        tblSearchResults.reloadData()
    }
}

在 viewDidLoad() 里面調用它

override func viewDidLoad() {
    ...

    loadListOfCountries()
}

更新數據,返回dataArray

 func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if shouldShowSearchResults {
        return filteredArray.count
    }
    else {
        return dataArray.count
    }
}

確定cell需要展示的內容

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCellWithIdentifier("idCell", forIndexPath: indexPath) as! UITableViewCell

    if shouldShowSearchResults {
        cell.textLabel?.text = filteredArray[indexPath.row]
    }
    else {
        cell.textLabel?.text = dataArray[indexPath.row]
    }

    return cell
}

下面我們來配置search controller 顯示默認的search bar

配置UISearchController

首先在 ViewController.swift 里面聲明一個searchController

var searchController: UISearchController!

接下來我們來實現 configureSearchController() 方法。

func configureSearchController() {
       // Initialize and perform a minimum configuration to the search controller.
       searchController = UISearchController(searchResultsController: nil)
       searchController.searchResultsUpdater = self
       searchController.dimsBackgroundDuringPresentation = false
       searchController.searchBar.placeholder = "Search here..."
       searchController.searchBar.delegate = self
       searchController.searchBar.sizeToFit()

       // Place the search bar view to the tableview headerview.
       tblSearchResults.tableHeaderView = searchController.searchBar
   }

這里有一個重要的知識點:在我們的demo中tableview顯示搜索結果是在一個已經存在的controller中,然而還有一種情況是把搜索結果展示到另外一個ViewController中,所以需要知道把搜索結果展示到哪里. 當初始化的時候傳 nil ,search controller 知道viewController已經存在,搜索數據回調到給這個viewController. 另外一種情況就是傳指定的controller。

在搜索的時候有兩種方法更新我們的tableview,第一種是通過searchbar的delegate。第二種是在delegate對象的Viewcontroller里面設置 searchResultsUpdater 屬性(bool),稍后會在自定義控制器中看見這個是如何使用的。

在這里我們通過實現 UISearchResultsUpdating 協議。這個是iOS8才有的.

func updateSearchResultsForSearchController(searchController: UISearchController) {
    let searchString = searchController.searchBar.text

    // Filter the data array and get only those countries that match the search text.
    filteredArray = dataArray.filter({ (country) -> Bool in
        let countryText: NSString = country

        return (countryText.rangeOfString(searchString, options: NSStringCompareOptions.CaseInsensitiveSearch).location) != NSNotFound
    })

    // Reload the tableview.
    tblSearchResults.reloadData()
}

這里用了 searchString 保存關鍵字,然后用filter過濾

最后實現 UISearchbarDelegate

 func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
    shouldShowSearchResults = true
    tblSearchResults.reloadData()
}


func searchBarCancelButtonClicked(searchBar: UISearchBar) {
    shouldShowSearchResults = false
    tblSearchResults.reloadData()
}

func searchBarSearchButtonClicked(searchBar: UISearchBar) {

    if !shouldShowSearchResults {

        shouldShowSearchResults = true
        tblSearchResults.reloadData()
    }
    searchController.searchBar.resignFirstResponder()
}

最后運行app

自定義Searchbar

創建一個UISearchBar的子類 CustomSearchBar .在這里,我們會創建一個自定義的初始化方法,傳遞 frame , font , text color 等參數,在此之前,先定義兩個屬性

 var preferredFont: UIFont!

var preferredTextColor: UIColor!

創建一個初始化方法,并且改變了searchBar的類型。設置了 translucent 屬性,背景是不透明的。

init(frame: CGRect, font: UIFont, textColor: UIColor) {
   super.init(frame: frame)

   self.frame = frame
   preferredFont = font
   preferredTextColor = textColor

   searchBarStyle = UISearchBarStyle.Prominent
   translucent = false

}

提示: searchbar 并不是單一的控件,textfield只是其中的一部分。另外searchbar有一個UIView作為子類,這個view里面包含textfield和一個backgroundView。 可以打印一下就知道了

print(searchController.searchBar.subviews[0].subviews)

將會輸出

我測試的時候輸出的是這樣的:layer那里有一個null?

[<UISearchBarBackground: 0x7fb771e8e7f0; frame = (0 0; 600 44); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7fb771e83cf0>> - (null), <UISearchBarTextField: 0x7fb771e97b70; frame = (0 0; 0 0); text = ''; clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x7fb771e969f0>>]

為了找到 searField ,寫一個找到子類的方法

 func indexOfSearchFieldInSubviews() -> Int! {
    var index: Int!
    let searchBarView = subviews[0] as! UIView

    for var i=0; i<searchBarView.subviews.count; ++i {
        if searchBarView.subviews[i].isKindOfClass(UITextField) {
            index = i
            break
        }
    }

    return index
}

接下來實現 drawRect 方法。 修改了textfield的大小,在底部添加了一條線

override func drawRect(rect: CGRect) {


       if let index = indexOfSearchFieldInSubviews() {

           let searchField : UITextField = (subviews[0]).subviews[index] as! UITextField

           searchField.frame = CGRectMake(5.0, 5.0, frame.size.width - 10.0, frame.size.height - 10.0)
           searchField.font = preferredFont
           searchField.textColor = preferredTextColor

           searchField.backgroundColor = barTintColor
       }

       let startPoint = CGPointMake(0.0, frame.size.height)
       let endPoint = CGPointMake(frame.size.width, frame.size.height)

       let path = UIBezierPath()
       path.moveToPoint(startPoint)
       path.addLineToPoint(endPoint)

       let shapeLayer = CAShapeLayer()
       shapeLayer.path = path.CGPath
       shapeLayer.strokeColor = preferredTextColor.CGColor
       shapeLayer.lineWidth = 2.5

       layer.addSublayer(shapeLayer);

       super.drawRect(rect)

   }

自定義SearchController

創建一個子類 CustomSearchController ,并且在里面增加 CustomSearchBar 的引用

var customSearchBar: CustomSearchBar!

自定義初始化方法

init(searchResultsController: UIViewController!, searchBarFrame: CGRect, searchBarFont: UIFont, searchBarTextColor: UIColor, searchBarTintColor: UIColor) {
    super.init(searchResultsController: searchResultsController)

    configureSearchBar(searchBarFrame, font: searchBarFont, textColor: searchBarTextColor, bgColor: searchBarTintColor)
}

需要添加兩個方法

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

configureSearchBar() 方法

 func configureSearchBar(frame: CGRect, font: UIFont, textColor: UIColor, bgColor: UIColor) {
    customSearchBar = CustomSearchBar(frame: frame, font: font , textColor: textColor)

    customSearchBar.barTintColor = bgColor
    customSearchBar.tintColor = textColor
    customSearchBar.showsBookmarkButton = false
    customSearchBar.showsCancelButton = true
}

在 viewController 里面初始化

 func configureCustomSearchController() {
    customSearchController = CustomSearchController(searchResultsController: self, searchBarFrame: CGRectMake(0.0, 0.0, tblSearchResults.frame.size.width, 50.0), searchBarFont: UIFont(name: "Futura", size: 16.0)!, searchBarTextColor: UIColor.orangeColor(), searchBarTintColor: UIColor.blackColor())

    customSearchController.customSearchBar.placeholder = "Search in this awesome bar..."
    tblSearchResults.tableHeaderView = customSearchController.customSearchBar
}

最后實現的效果

完整的demo下載

參考demo

來自: http://www.liuchendi.com/2016/01/06/iOS/30_SearchBar/

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!