So far, you learned how to implement these features of the UICollectionView class:
Today you’ll learn how to implement these features in the SwiftCollectionView application:
- Search the collection view by typing text in a Search Bar’s text field.
- Dismiss the keyboard by tapping the Search Bar’s Cancel button.
- Dismiss the keyboard by double-tapping the collection view’s background.
Take a look at this QuickTime video, it show results of implementing the search bar and keyboard dismissal feature in the SwiftCollectionView application.
Create a New Branch
Ok, start things off by launching the SwiftCollectionView project in Xcode. Use the Source Control menu to create a new branch. Call it search-collection-view.
Add New Scene on The Storyboard
Now, in order to implement the search feature in the project, you’ll have to add a new scene on the storyboard canvas and configure it so it look like the one shown in Figure 6-2 below. Start by clicking the Main.storyboard file to load it in Interface Builder. Now do the following:
- Delete the Collection View Controller scene and its Navigation Controller.
- Drag a View Controller from the Object Library and drop it on the storyboard canvas.
- Embed the View Controller scene in a Navigation Controller (Editor | Embed In | Navigation Controller).
- Click the Collection View scene’s Navigation Controller scene.
- In the Attributes inspector, tick the Is Initial View Controller checkbox. This make the Collection View scene the initial scene.
- Drag a Search Bar from the Object Library and drop it below the View Controller scene’ Navigation Item. Make sure it is the same width as the scene-see Figure 6-2 below.
- Click the Search Bar. Locate the Placeholder field in the Attributes Inspector and enter this text: Enter the photo name here
- Locate the Shows Cancel Button checkbox in the Attributes Inspector and tick it. This place a Cancel button on the Search Bar-see Figure 6-2 below.
- Drag a Collection View from the Object Library and drop it below the Search Bar. Make sure it cover remaining surface of the scene-see Figure 6-2 below.
- Click the Collection View Cell, locate the Identifier field in the Attributes Inspector, enter this text: Cell. Next, locate the Keyboard menu. It’s located in the Scroll View section. Select the Dismiss on drag option. This dismiss the keyboard and reset the collection view back its default mode.
- Control-click the Collection View Cell and drag resulting blue line to the Photo Detail scene’s Navigation Bar Scene. Release your mouse when the Navigation Controller scene is highlighted. Select present modally from the pop up menu.
- Click the segue you created for the Collection View Cell. Locate the Identifier field in the Attributes Inspector and enter this text: photoDetail
- Click the Collection View. In the Size Inspector, add sizes shown in Figure 6-1 below.
- Click the View Controller scene’s Navigation Item. Locate the Title field in the Attributes Inspector and enter this text: Photos
- Click the View Controller scene object, locate the Class menu in the Identity Inspector, and select MasterViewController option.
- Select the View Controller object and use the Auto Layout bar’s Issues button to add missing constraints to the default Size Class; which is wAny hAny.
That’s it you are done designing the new scene. Rearrange the scenes so they look like Figure 6-3.
![]() |
![]() |
| Figure 6-1 | Figure 6-2 |
![]() |
|
| Figure 6-3 | |
The Search Bar and Collection View Connections
In Interface Builder, you have to do the following for the Search Bar and the Collection View you added on the Photos scene:
- Connect the Search Bar’s delegate outlet to the Photos scene object via the Connections Inspector.
- Create and connect an IBOutlet variable called searchBar via the Assistant editor.
- Connect the Collection View’s dataSource and delegate outlets via the Connections Inspector.
- Create and connect an IBOutlet variable called collectionView via the Assistant Editor.
Once you’ve perform above tasks, the Connections Inspector for the Photos scene’s Search Bar and the Collection View should look like these images:
![]() |
![]() |
| Figure 6-4: Search Bar Connections | Figure 6-5: Collection View Connections |
The Master View Controller Class Code
That’s it; you are done with the Main.storyboard, so switch to the MasterViewController.swift file because you will be adding code in it to implement the collection view search feature and to dismiss the on-screen keyboard.
Start by scrolling to the end of the MasterViewController.swift file and add code shown below, just above the class file’s closing } bracket.
// MARK: UISearchBarDelegate functions
// This function is fired when the user tap the Search Bar's Cancel button
func searchBarCancelButtonClicked(searchBar: UISearchBar!) {
searchBar.text = nil // Clear out the Search Bar's text field
searchBar.showsCancelButton = false // Hide the Search Bar's Cancel button
searchBar.resignFirstResponder() // Dismiss the keyboard
isSearchOn = false // Turn off search function
self.collectionView.reloadData() // Refresh the collection view
}
// this function is fired when the user start entering text in the Search Bar's text field
func searchBar(searchBar: UISearchBar!, textDidChange searchText: String!) {
searchBar.showsCancelButton = true // Show the Search Bar's Cancel button
if !searchText.isEmpty {
isSearchOn = true // Turn on searching function
self.filterContentForSearchText() // Search the collection view's dataSource
self.collectionView.reloadData()
}
}
Here are the helper functions for the UISearchBarDelegate functions. Add them in the MasterViewController.swift file.
// MARK: Helper functions for the UISearchBarDelegate functions
// This function search the collection view's dataSource object (imageFileNames)for an item that match
// text entered in the Search Bar's text field. If any items found, add them in the searchResults array
func filterContentForSearchText() {
// Remove all elements from the searchResults array
searchResults.removeAll(keepCapacity: false)
// Loop throught the collection view's dataSource object
for imageFileName in imageFileNames {
let stringToLookFor = imageFileName as NSString
let sourceString = searchBar.text as NSString
if stringToLookFor.localizedCaseInsensitiveContainsString(sourceString) {
// Match found, so add it to the searchResults array variable
searchResults.append(imageFileName)
}
}
}
// Target function for the tap gesture recognizer object created in the viewDidLoad function
func collectionViewBackgroundTapped() {
// Dismiss the keyboard that's shown on the device's screen
searchBar.resignFirstResponder()
}
/***********************
This function allow the default tap gesture added to the collection view cell,
an the collection view's background to to work simultaneously
**************************/
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOfGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
// Perform default tap gesture
return true
}
}
Now, scroll up to the top of the MasterViewController.swift and change its code to this:
import UIKit
let reuseIdentifier = "Cell"
class MasterViewController: UIViewController, UISearchBarDelegate, UIGestureRecognizerDelegate {
@IBOutlet weak var editButton: UIBarButtonItem!
@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var collectionView: UICollectionView!
var icon: PhotoCell!
var imageFileNames = [String]()
var selectedPhotoName = String()
var isSearchOn = false
var searchResults = [String]()
Modify the viewDidLoad function’s code to this:
override func viewDidLoad() {
super.viewDidLoad()
// Set the collection view's backgroundcolor to display an image
self.collectionView!.backgroundColor = UIColor(patternImage: UIImage(named: "purty_wood")!)
// Register the class with the collection view
self.collectionView!.registerClass(PhotoCell.self, forCellWithReuseIdentifier: reuseIdentifier)
// Add objects in the collection view dataSource, imageFileNames Array
loadImages()
//1. Create a tap gesture recognizer object
let tapRecognizer = UITapGestureRecognizer()
tapRecognizer.numberOfTapsRequired = 2
//2. Set the target function for the tap gesture recognizer object
tapRecognizer.addTarget(self, action: "collectionViewBackgroundTapped")
//3. Add the tap gesture recognizer to the collection view
self.collectionView.addGestureRecognizer(tapRecognizer)
}
Scroll down to the collection view data source functions and change their code to those shown below:
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
// Return the number of sections
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// Return the number of items in the section
// Return the number of items in a section (number of photos in an album)
if isSearchOn == true && !searchResults.isEmpty {
return searchResults.count
} else {
return imageFileNames.count
}
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
// Initialize the reusable Collection View Cell with our custom class
icon = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as PhotoCell
var photoName = String()
// Initialize the photoName variable with an item in the searchResults array or an item in the imageFileNames array
if isSearchOn == true && !searchResults.isEmpty {
photoName = searchResults[indexPath.item]
} else {
photoName = imageFileNames[indexPath.item]
}
// Configure the collection view cell
icon.imageView.image = UIImage(named: photoName)
var stringArray: Array = photoName.componentsSeparatedByString(".")
icon.caption.text = stringArray[0]
// Return the cell
return icon
}
Also, change the collection view delegate function’s code to this:
// MARK: UICollectionViewDelegate
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
// Put the selected collection view cell's photo file name in a variable
if isSearchOn == true && !searchResults.isEmpty {
selectedPhotoName = searchResults[indexPath.row] as String
} else {
selectedPhotoName = imageFileNames[indexPath.row] as String
}
// Pass control to the PhotoDetailViewController
self.performSegueWithIdentifier("photoDetail", sender:self)
}
The last thing I want you to do is, change the PhotoCell.swift file’s code so it look like this:
import UIKit
class PhotoCell: UICollectionViewCell {
// The collection view cell's objects
var imageView: UIImageView!
var caption: UILabel!
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
// Create an ImageView and add it to the collection view
imageView = UIImageView(frame: CGRect(x:30, y:12, width:55, height:55))
imageView.contentMode = UIViewContentMode.ScaleAspectFill
contentView.addSubview(imageView)
// Create a Label view and add it to the collection view
let textFrame = CGRect(x:5, y:67, width:100, height:35)
caption = UILabel(frame: textFrame)
caption.font = UIFont.systemFontOfSize(14.0)
caption.textAlignment = .Center
caption.numberOfLines = 2
caption.lineBreakMode = NSLineBreakMode.ByWordWrapping
caption.textColor = UIColor.whiteColor()
caption.backgroundColor = UIColor.blackColor()
contentView.addSubview(caption)
}
}
Go ahead and run the app in the iOS Simulator and test the Search Bar’s and code, and the keyboard dismissal code. The app should function just like the one shown in above QuickTime video.
That’s All Folks!
That’s all for phase 6 of the SwiftCollectionView app. Next week, you will learn how to implement these features in the app:
- Fetch image urls from a plist file, add them in the collection view’s dataSource variable.
- Load the photo urls’ images in the collection view cells
. Until then, happy coding! 🙂




