iOS-Tutorial-Lecture 5 Slides
iOS-Tutorial-Lecture 5 Slides
CS193p
Spring 2016
Today
Interface Builder Demo
Viewing and editing your custom UIViews in your storyboard (FaceView)
Gestures
Getting touch input from users
Multiple MVCs
Tab Bar, Navigation and Split View Controller
CS193p
Spring 2016
Demo
Interface Builder Demo
Viewing and editing your custom UIViews in your storyboard (FaceView)
CS193p
Spring 2016
Gestures
We’ve seen how to draw in a UIView, how do we get touches?
We can get notified of the raw touch events (touch down, moved, up, etc.)
Or we can react to certain, predefined “gestures.” The latter is the way to go!
CS193p
Spring 2016
Gestures
Adding a gesture recognizer to a UIView
Imagine we wanted a UIView in our Controller’s View to recognize a “pan” gesture.
We can configure it to do so in the property observer for the outlet to said UIView …
@IBOutlet weak var pannableView: UIView {
didSet {
let recognizer = UIPanGestureRecognizer(
target: self, action: #selector(ViewController.pan(_:))
)
pannableView.addGestureRecognizer(recognizer)
}
}
CS193p
Spring 2016
Gestures
Adding a gesture recognizer to a UIView
Imagine we wanted a UIView in our Controller’s View to recognize a “pan” gesture.
We can configure it to do so in the property observer for the outlet to said UIView …
@IBOutlet weak var pannableView: UIView {
didSet {
let recognizer = UIPanGestureRecognizer(
target: self, action: #selector(ViewController.pan(_:))
)
pannableView.addGestureRecognizer(recognizer)
}
}
The property observer’s didSet code gets called when iOS hooks up this outlet at runtime.
CS193p
Spring 2016
Gestures
Adding a gesture recognizer to a UIView
Imagine we wanted a UIView in our Controller’s View to recognize a “pan” gesture.
We can configure it to do so in the property observer for the outlet to said UIView …
@IBOutlet weak var pannableView: UIView {
didSet {
let recognizer = UIPanGestureRecognizer(
target: self, action: #selector(ViewController.pan(_:))
)
pannableView.addGestureRecognizer(recognizer)
}
}
The property observer’s didSet code gets called when iOS hooks up this outlet at runtime.
Here we are creating an instance of a concrete subclass of UIGestureRecognizer (for pans)
CS193p
Spring 2016
Gestures
Adding a gesture recognizer to a UIView
Imagine we wanted a UIView in our Controller’s View to recognize a “pan” gesture.
We can configure it to do so in the property observer for the outlet to said UIView …
@IBOutlet weak var pannableView: UIView {
didSet {
let recognizer = UIPanGestureRecognizer(
target: self, action: #selector(ViewController.pan(_:))
)
pannableView.addGestureRecognizer(recognizer)
}
}
The property observer’s didSet code gets called when iOS hooks up this outlet at runtime.
Here we are creating an instance of a concrete subclass of UIGestureRecognizer (for pans)
The target gets notified when the gesture is recognized (in this case, the Controller itself)
CS193p
Spring 2016
Gestures
Adding a gesture recognizer to a UIView
Imagine we wanted a UIView in our Controller’s View to recognize a “pan” gesture.
We can configure it to do so in the property observer for the outlet to said UIView …
@IBOutlet weak var pannableView: UIView {
didSet {
let recognizer = UIPanGestureRecognizer(
target: self, action: #selector(ViewController.pan(_:))
)
pannableView.addGestureRecognizer(recognizer)
}
}
The property observer’s didSet code gets called when iOS hooks up this outlet at runtime.
Here we are creating an instance of a concrete subclass of UIGestureRecognizer (for pans)
The target gets notified when the gesture is recognized (in this case, the Controller itself)
The action is the method invoked on recognition ((_:) means the method has an argument)
CS193p
Spring 2016
Gestures
Adding a gesture recognizer to a UIView
Imagine we wanted a UIView in our Controller’s View to recognize a “pan” gesture.
We can configure it to do so in the property observer for the outlet to said UIView …
@IBOutlet weak var pannableView: UIView {
didSet {
let recognizer = UIPanGestureRecognizer(
target: self, action: #selector(ViewController.pan(_:))
)
pannableView.addGestureRecognizer(recognizer)
}
}
The property observer’s didSet code gets called when iOS hooks up this outlet at runtime.
Here we are creating an instance of a concrete subclass of UIGestureRecognizer (for pans)
The target gets notified when the gesture is recognized (in this case, the Controller itself)
The action is the method invoked on recognition ((_:) means the method has an argument)
Here we ask the UIView to actually start trying to recognize this gesture in its bounds
CS193p
Spring 2016
Gestures
Adding a gesture recognizer to a UIView
Imagine we wanted a UIView in our Controller’s View to recognize a “pan” gesture.
We can configure it to do so in the property observer for the outlet to said UIView …
@IBOutlet weak var pannableView: UIView {
didSet {
let recognizer = UIPanGestureRecognizer(
target: self, action: #selector(ViewController.pan(_:))
)
pannableView.addGestureRecognizer(recognizer)
}
}
The property observer’s didSet code gets called when iOS hooks up this outlet at runtime.
Here we are creating an instance of a concrete subclass of UIGestureRecognizer (for pans)
The target gets notified when the gesture is recognized (in this case, the Controller itself)
The action is the method invoked on recognition ((_:) means the method has an argument)
Here we ask the UIView to actually start trying to recognize this gesture in its bounds
Let’s talk about how we implement the handler … CS193p
Spring 2016
Gestures
A handler for a gesture needs gesture-specific information
So each concrete subclass provides special methods for handling that type of gesture
Spring 2016
Gestures
So, given this information, what would the pan handler look like?
func pan(gesture: UIPanGestureRecognizer) {
switch gesture.state {
case .Changed: fallthrough
case .Ended:
let translation = gesture.translationInView(pannableView)
// update anything that depends on the pan gesture using translation.x and .y
gesture.setTranslation(CGPointZero, inView: pannableView)
default: break
}
}
Remember that the action was pan(_:) (if no _:, then no gesture argument)
CS193p
Spring 2016
Gestures
So, given this information, what would the pan handler look like?
func pan(gesture: UIPanGestureRecognizer) {
switch gesture.state {
case .Changed: fallthrough
case .Ended:
let translation = gesture.translationInView(pannableView)
// update anything that depends on the pan gesture using translation.x and .y
gesture.setTranslation(CGPointZero, inView: pannableView)
default: break
}
}
Remember that the action was pan(_:) (if no _:, then no gesture argument)
We are only going to do anything when the finger moves or lifts up off the device’s surface
CS193p
Spring 2016
Gestures
So, given this information, what would the pan handler look like?
func pan(gesture: UIPanGestureRecognizer) {
switch gesture.state {
case .Changed: fallthrough
case .Ended:
let translation = gesture.translationInView(pannableView)
// update anything that depends on the pan gesture using translation.x and .y
gesture.setTranslation(CGPointZero, inView: pannableView)
default: break
}
}
Remember that the action was pan(_:) (if no _:, then no gesture argument)
We are only going to do anything when the finger moves or lifts up off the device’s surface
fallthrough is “execute the code for the next case down” (case .Changed,.Ended: ok too)
CS193p
Spring 2016
Gestures
So, given this information, what would the pan handler look like?
func pan(gesture: UIPanGestureRecognizer) {
switch gesture.state {
case .Changed: fallthrough
case .Ended:
let translation = gesture.translationInView(pannableView)
// update anything that depends on the pan gesture using translation.x and .y
gesture.setTranslation(CGPointZero, inView: pannableView)
default: break
}
}
Remember that the action was pan(_:) (if no _:, then no gesture argument)
We are only going to do anything when the finger moves or lifts up off the device’s surface
fallthrough is “execute the code for the next case down” (case .Changed,.Ended: ok too)
Here we get the location of the pan in the pannableView’s coordinate system
CS193p
Spring 2016
Gestures
So, given this information, what would the pan handler look like?
func pan(gesture: UIPanGestureRecognizer) {
switch gesture.state {
case .Changed: fallthrough
case .Ended:
let translation = gesture.translationInView(pannableView)
// update anything that depends on the pan gesture using translation.x and .y
gesture.setTranslation(CGPointZero, inView: pannableView)
default: break
}
}
Remember that the action was pan(_:) (if no _:, then no gesture argument)
We are only going to do anything when the finger moves or lifts up off the device’s surface
fallthrough is “execute the code for the next case down” (case .Changed,.Ended: ok too)
Here we get the location of the pan in the pannableView’s coordinate system
Now we do whatever we want with that information
CS193p
Spring 2016
Gestures
So, given this information, what would the pan handler look like?
func pan(gesture: UIPanGestureRecognizer) {
switch gesture.state {
case .Changed: fallthrough
case .Ended:
let translation = gesture.translationInView(pannableView)
// update anything that depends on the pan gesture using translation.x and .y
gesture.setTranslation(CGPointZero, inView: pannableView)
default: break
}
}
Remember that the action was pan(_:) (if no _:, then no gesture argument)
We are only going to do anything when the finger moves or lifts up off the device’s surface
fallthrough is “execute the code for the next case down” (case .Changed,.Ended: ok too)
Here we get the location of the pan in the pannableView’s coordinate system
Now we do whatever we want with that information
By resetting the translation, the next one we get will be incremental movement CS193p
Spring 2016
Gestures
UIPinchGestureRecognizer
var scale: CGFloat // not read-only (can reset)
var velocity: CGFloat { get } // scale factor per second
UIRotationGestureRecognizer
var rotation: CGFloat // not read-only (can reset); in radians
var velocity: CGFloat { get } // radians per second
UISwipeGestureRecognizer
Set up the direction and number of fingers you want, then look for .Recognized
var direction: UISwipeGestureRecoginzerDirection // which swipes you want
var numberOfTouchesRequired: Int // finger count
UITapGestureRecognizer
Set up the number of taps and fingers you want, then look for .Ended
var numberOfTapsRequired: Int // single tap, double tap, etc.
var numberOfTouchesRequired: Int // finger count
CS193p
Spring 2016
Demo
Gestures Demo
Add a gesture recognizer (pinch) to the FaceView to zoom in and out (control its own scale)
Add a gesture recognizer (pan) to the FaceView to control expression (Model) in the Controller
CS193p
Spring 2016
MVCs working together
CS193p
Spring 2016
Multiple MVCs
Time to build more powerful applications
To do this, we must combine MVCs …
Spring 2016
Multiple MVCs
Time to build more powerful applications
To do this, we must combine MVCs …
CS193p
Spring 2016
UITabBarController
It lets the user choose between different MVCs …
A “Dashboard” MVC
CS193p
Spring 2016
UITabBarController
It lets the user choose between different MVCs …
CS193p
Spring 2016
UITabBarController
It lets the user choose between different MVCs …
CS193p
Spring 2016
UISplitViewController
Puts two MVCs side-by-side …
A
Calculator
MVC
Master
CS193p
Spring 2016
UISplitViewController
Puts two MVCs side-by-side …
A A
Calculator Calculator Graph
MVC MVC
Master Detail
CS193p
Spring 2016
UISplitViewController
Puts two MVCs side-by-side …
A A
Calculator Calculator Graph
MVC MVC
Master Detail
CS193p
Spring 2016
UISplitViewController
Puts two MVCs side-by-side …
A A
Calculator Calculator Graph
MVC MVC
Master Detail
CS193p
Spring 2016
UINavigationController
Pushes and pops MVCs off of a stack (like a stack of cards) …
CS193p
Spring 2016
UINavigationController
Pushes and pops MVCs off of a stack (like a stack of cards) …
CS193p
Spring 2016
UINavigationController
Pushes and pops MVCs off of a stack (like a stack of cards) …
CS193p
Spring 2016
UINavigationController
Pushes and pops MVCs off of a stack (like a stack of cards) …
CS193p
Spring 2016
UINavigationController
Pushes and pops MVCs off of a stack (like a stack of cards) …
CS193p
Spring 2016
UINavigationController
Pushes and pops MVCs off of a stack (like a stack of cards) …
An “Accessibility” MVC
CS193p
Spring 2016
UINavigationController
Pushes and pops MVCs off of a stack (like a stack of cards) …
CS193p
Spring 2016
UINavigationController
Pushes and pops MVCs off of a stack (like a stack of cards) …
CS193p
Spring 2016
UINavigationController
Pushes and pops MVCs off of a stack (like a stack of cards) …
CS193p
Spring 2016
UINavigationController
Pushes and pops MVCs off of a stack (like a stack of cards) …
CS193p
Spring 2016
UINavigationController
Pushes and pops MVCs off of a stack (like a stack of cards) …
CS193p
Spring 2016
UINavigationController
Pushes and pops MVCs off of a stack (like a stack of cards) …
CS193p
Spring 2016
UINavigationController
Pushes and pops MVCs off of a stack (like a stack of cards) …
CS193p
Spring 2016
UINavigationController
Pushes and pops MVCs off of a stack (like a stack of cards) …
CS193p
Spring 2016
UINavigationController
Spring 2016
UINavigationController
Spring 2016
UINavigationController
CS193p
Spring 2016
UINavigationController
The UINavigationController is a
UINavigationController
Controller whose View looks like this.
CS193p
Spring 2016
UINavigationController
UINavigationController
ro
ot
Vi
ew
Co
nt
ro But it’s special because we can set its
ll
er rootViewController outlet to another MVC ...
CS193p
Spring 2016
UINavigationController
... and it will embed that MVC’s
UINavigationController
View inside its own View.
CS193p
Spring 2016
UINavigationController
UINavigationController
Then a UI element in this View (e.g. a UIButton) can segue to the other
MVC and its View will now appear in the UINavigationController instead.
CS193p
Spring 2016
UINavigationController
UINavigationController
CS193p
Spring 2016
UINavigationController
UINavigationController
CS193p
Spring 2016
UINavigationController
UINavigationController
CS193p
Spring 2016
UINavigationController
UINavigationController
Spring 2016
UINavigationController
UINavigationController
CS193p
Spring 2016
Accessing the sub-MVCs
You can get the sub-MVCs via the viewControllers property
var viewControllers: [UIViewController]? { get set } // can be optional (e.g. for tab bar)
// for a tab bar, they are in order, left to right, in the array
// for a split view, [0] is the master and [1] is the detail
// for a navigation controller, [0] is the root and the rest are in order on the stack
// even though this is settable, usually setting happens via storyboard, segues, or other
// for example, navigation controller’s push and pop methods
Spring 2016
Wiring up MVCs
How do we wire all this stuff up?
Let’s say we have a Calculator MVC and a Calculator Graphing MVC
How do we hook them up to be the two sides of a Split View?
Just drag out a (and delete all the extra VCs it brings with it)
Then ctrl-drag from the UISplitViewController to the master and detail MVCs …
CS193p
Spring 2016
Wiring up MVCs
CS193p
Spring 2016
Wiring up MVCs
CS193p
Spring 2016
Wiring up MVCs
CS193p
Spring 2016
Wiring up MVCs
CS193p
Spring 2016
Wiring up MVCs
CS193p
Spring 2016
Wiring up MVCs
But split view can only do its thing properly on iPad
So we need to put some Navigation Controllers in there so it will work on iPhone
The Navigation Controllers will be good for iPad too because the MVCs will get titles
The simplest way to wrap a Navigation Controller around an MVC is with Editor->Embed In
CS193p
Spring 2016
Wiring up MVCs
But split view can only do its thing properly on iPad
So we need to put some Navigation Controllers in there so it will work on iPhone
The Navigation Controllers will be good for iPad too because the MVCs will get titles
The simplest way to wrap a Navigation Controller around an MVC is with Editor->Embed In
Spring 2016
Wiring up MVCs
But split view can only do its thing properly on iPad
So we need to put some Navigation Controllers in there so it will work on iPhone
The Navigation Controllers will be good for iPad too because the MVCs will get titles
The simplest way to wrap a Navigation Controller around an MVC is with Editor->Embed In
CS193p
Spring 2016
Wiring up MVCs
But split view can only do its thing properly on iPad
So we need to put some Navigation Controllers in there so it will work on iPhone
The Navigation Controllers will be good for iPad too because the MVCs will get titles
The simplest way to wrap a Navigation Controller around an MVC is with Editor->Embed In
CS193p
Spring 2016