UIScrollView Tutorial: Getting Started
In this UIScrollView tutorial, you’ll create an app similar to the default iOS Photos app to learn all about paging, scrolling and more with UIScrollView. By Ron Kliffer.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
UIScrollView Tutorial: Getting Started
30 mins
- Getting Started
- Scrolling and Zooming a Large Image
- Panning and Zooming Your Image
- Setting the Zoom Scale
- Centering Your Image
- Scrolling Vertically
- Scroll View and Auto Layout
- Adding a Label to Your Image
- Displaying Properly in Every Orientation
- Scrolling to See More
- Managing the Keyboard
- Dismissing the Keyboard
- Paging With UIPageViewController
- Getting Set Up
- Creating and Implementing Your Page View Controller
- Fixing Your App's Flow
- Displaying a Page Control Indicator
- Putting It All Together
- Where to Go From Here?
Managing the Keyboard
Unlike UITableViewController
, which automatically handles moving content out of the way of the keyboard, you have to manage the keyboard manually when you use a UIScrollView
directly.
Do this by making PhotoCommentViewController
observe the keyboard Notification
objects that iOS sends whenever the keyboard hides and displays.
To do this, open PhotoCommentViewController.swift and add the following methods:
//1
func adjustInsetForKeyboardShow(_ show: Bool, notification: Notification) {
guard
let userInfo = notification.userInfo,
let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey]
as? NSValue
else {
return
}
let adjustmentHeight = (keyboardFrame.cgRectValue.height + 20) * (show ? 1 : -1)
scrollView.contentInset.bottom += adjustmentHeight
scrollView.verticalScrollIndicatorInsets.bottom += adjustmentHeight
}
//2
@objc func keyboardWillShow(_ notification: Notification) {
adjustInsetForKeyboardShow(true, notification: notification)
}
@objc func keyboardWillHide(_ notification: Notification) {
adjustInsetForKeyboardShow(false, notification: notification)
}
Here’s what you’re doing with this code:
- In
adjustInsetForKeyboardShow(_:notification:)
, you extract the keyboard height from thenotification
‘suserInfo
and set the scroll view’s insets accordingly. - You call
adjustInsetForKeyboardShow(_:)
when the user hides or shows the keyboard, indicating the direction to move the scroll view.
Next, you need to set up the observers for the keyboard changes. Add the following code at the bottom of viewDidLoad()
:
NotificationCenter.default.addObserver(
self,
selector: #selector(keyboardWillShow(_:)),
name: UIResponder.keyboardWillShowNotification,
object: nil)
NotificationCenter.default.addObserver(
self,
selector: #selector(keyboardWillHide(_:)),
name: UIResponder.keyboardWillHideNotification,
object: nil)
Dismissing the Keyboard
To dismiss the keyboard, add this method to PhotoCommentViewController.swift:
@IBAction func hideKeyboard(_ sender: AnyObject) {
nameTextField.endEditing(true)
}
This method will resign the first responder status of the text field, which, in turn, dismisses the keyboard.
Finally, open Main.storyboard, and drag a Tap Gesture Recognizer onto the View in the Photo Comment View Controller scene. Then, wire it to the hideKeyboard(_:)
IBAction
in PhotoCommentViewController
.
To make it more user friendly, the keyboard should also dismiss when the user presses the return key. Right-click on nameTextField
and wire Primary Action Triggered to hideKeyboard(_:)
.
Build and run.
Now, navigate to the Photo Comment View Controller scene. Tap the text field and then tap somewhere else on the view. The keyboard should properly show and hide itself relative to the other content on the screen. Likewise, tapping the return key does the same.
Paging With UIPageViewController
In the third section of this UIScrollView
tutorial, you’ll create a scroll view that allows paging, meaning that the scroll view locks onto a page when you stop dragging. You can see this in action in the App Store app when you view screenshots of an app.
Getting Set Up
Go to Main.storyboard and drag a Page View Controller onto the canvas. Open the Identity inspector and enter PageViewController for the Storyboard ID.
In the Attributes inspector, the Transition Style is set to Page Curl by default. Change it to Scroll and set the Page Spacing to 8.
In the Photo Comment View Controller scene’s Identity inspector, specify a Storyboard ID of PhotoCommentViewController. This lets you refer to the storyboard from your code.
Open PhotoCommentViewController.swift and add this property after the others:
var photoIndex: Int!
This references the index of the photo to display. The page view controller will use this property.
Creating and Implementing Your Page View Controller
Now, create a new file with the iOS ▸ Source ▸ Cocoa Touch Class template. Name the class ManagePageViewController and set the subclass to UIPageViewController.
Open ManagePageViewController.swift and replace the contents of the file with the following:
import UIKit
class ManagePageViewController: UIPageViewController {
var photos = ["photo1", "photo2", "photo3", "photo4", "photo5"]
var currentIndex: Int!
override func viewDidLoad() {
super.viewDidLoad()
// 1
if let viewController = viewPhotoCommentController(currentIndex ?? 0) {
let viewControllers = [viewController]
// 2
setViewControllers(viewControllers,
direction: .forward,
animated: false,
completion: nil)
}
}
func viewPhotoCommentController(_ index: Int) -> PhotoCommentViewController? {
guard
let storyboard = storyboard,
let page = storyboard
.instantiateViewController(withIdentifier: "PhotoCommentViewController")
as? PhotoCommentViewController
else {
return nil
}
page.photoName = photos[index]
page.photoIndex = index
return page
}
}
Here’s what this code does:
-
viewPhotoCommentController(_:)
creates an instance ofPhotoCommentViewController
through the storyboard. You pass the name of the image as a parameter so the displayed view matches the image you selected in the previous screen. - You set up the
UIPageViewController
by passing it an array that contains the single view controller you just created.
Now that you’ve taken care of that, you need to implement UIPageViewControllerDataSource
. Add the following class extension to the end of this file:
extension ManagePageViewController: UIPageViewControllerDataSource {
func pageViewController(
_ pageViewController: UIPageViewController,
viewControllerBefore viewController: UIViewController)
-> UIViewController? {
if let viewController = viewController as? PhotoCommentViewController,
let index = viewController.photoIndex,
index > 0 {
return viewPhotoCommentController(index - 1)
}
return nil
}
func pageViewController(
_ pageViewController: UIPageViewController,
viewControllerAfter viewController: UIViewController)
-> UIViewController? {
if let viewController = viewController as? PhotoCommentViewController,
let index = viewController.photoIndex,
(index + 1) < photos.count {
return viewPhotoCommentController(index + 1)
}
return nil
}
}
UIPageViewControllerDataSource
allows you to provide content when the page changes. You provide view controller instances for paging both forward and backward. In both cases, you use photoIndex
to determine which image is currently displayed.
Both methods use the viewController
parameter to indicate the currently-displayed view controller. Using the photoIndex
, it creates and returns a new controller.
You also need to set the dataSource
. Add the following to the end of viewDidLoad()
:
dataSource = self
There are only a couple things left to do to get your page view running. First, you'll fix the flow of the app.
Fixing Your App's Flow
Switch back to Main.storyboard and select your newly-created Page View Controller scene. In the Identity inspector, specify ManagePageViewController for its class.
Delete the push segue showPhotoPage you created earlier. Then control-drag from Photo Cell in Scroll View Controller to Manage Page View Controller Scene and select a Show segue. In the Attributes inspector for the segue, specify its name as showPhotoPage, as you did before.
Open CollectionViewController.swift and change the implementation of prepare(for:sender:)
to the following:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let cell = sender as? UICollectionViewCell,
let indexPath = collectionView?.indexPath(for: cell),
let managePageViewController = segue.destination as? ManagePageViewController {
managePageViewController.photos = photos
managePageViewController.currentIndex = indexPath.row
}
}
Build and run.
You can now scroll sideways to page between different detail views.