By Kevin Hou
7 minute read
I am designing and implementing a profile screen into Breathometer’s new app and one of the key components of many profile screens is a profile picture. I’m continuing to add to my toolbox of Swift skills so I set about learning how to get pictures from either the camera app or phone’s photo library.
We need to build some basic frontend components so that we can have control over our code: ImageView: A view that our image from the camera/photo library will populate Button: To control when we want to upload the image
In order to use photos from the device, you must use the UIImagePickerControllerDelegate
and the UINavigationControllerDelegate
. These will give you the necessary functions to be able to retrieve your first image. The UIImagePickerControllerDelegate
is responsible for initiating an image picker controller which then piggybacks with the UINavigationControllerDelegate
that allows you to present the image picker using presentViewController()
and dismissViewControllerAnimated()
. Your view controller class should look like this:
1class ProfileScreen: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
2 override func viewDidLoad() {
3 super.viewDidLoad()
4 }
5}
6
Create an outlet for the imageView and an action outlet for the button:
1@IBOutlet weak var profilePictureImageView: UIImageView! // Image view we want to display the image in
2@IBAction func selectProfilePicture(sender: AnyObject) {
3}
4
Initialize the UIImagePickerController under the UIImageView outlet we created earlier:
1let imagePicker = UIImagePickerController() // Initialize an image picker view controller type
2
Now we can create a function that will serve up the image picker. It accepts a sourceType as an input so that the image picker knows whether to show the actual camera interface or the photo library interface. There are three main parts in displaying an image picker: editing, source type, and presenting. Source type can be from the camera, the camera roll, or the photo library. The presentation component is what actually presents the imagePicker controller.
1func pickImage(sourceType: UIImagePickerControllerSourceType) {
2 imagePicker.allowsEditing = false // Prevent editing
3
4 // Three sources: .PhotoLibrary, .Camera, .SavedPhotosAlbum
5 self.imagePicker.sourceType = sourceType // Type of image selection
6
7 // Presenting image picker view controller on top of stack
8 self.presentViewController(self.imagePicker, animated: true, completion: {
9 print("Opening image picker view controller")
10 })
11}
12
We want the user to be able to specify if they want to use their camera or the photo library to select an image. We give them this option by creating an action sheet. An action sheet looks like this:
Because we want this action sheet to appear when the button is pressed, we place this bit of code in the action outlet. The code is straightforward and intuitive:
1let imageSourcePicker = UIAlertController(title: "Select Profile Picture", message: "Please select an image picker method", preferredStyle: .ActionSheet) // Initialize action sheet type
2
3let cameraAction = UIAlertAction(title: "Take a picture", style: .Default, handler: { action in
4 self.pickImage(.Camera) // Presents picker
5})
6
7let cameraRoll = UIAlertAction(title: "Choose from camera roll", style: .Default, handler: { action in
8 self.pickImage(.PhotoLibrary) // Presents picker
9})
10
11// Add actions
12imageSourcePicker.addAction(cameraAction)
13imageSourcePicker.addAction(cameraRoll)
14
15presentViewController(imageSourcePicker, animated: true, completion: nil)
16
We must set the imagePicker delegate to self in viewDidLoad():
1imagePicker.delegate = self // States that this view controller will also handle the events
2
Now we can write the methods. There are two image picker functions are essential:
1imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) 2
This function is triggered when you return a valid image. The selected image is passed in as part of the info object.
1func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
2 if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
3 // If returned a valid image
4 profilePictureImageView.contentMode = .ScaleAspectFit // Set content setting
5 profilePictureImageView.image = pickedImage // Set image
6 }
7
8 // Dismiss the image picker controller
9 dismissViewControllerAnimated(true, completion: {
10 print("Dismissed image picker controller")
11 })
12}
13
14imagePickerControllerDidCancel(picker: UIImagePickerController)
15This is triggered when the image selection flow is cancelled
16func imagePickerControllerDidCancel(picker: UIImagePickerController) {
17 // Dismiss the image picker controller
18 dismissViewControllerAnimated(true, completion: {
19 print("Cancelled image picker flow")
20
21 })
22}
23
The complete source code looks like this:
1// Created by Kevin
2// Copyright © 2016 KevinHou. All rights reserved.
3//
4
5import Foundation
6import UIKit
7
8class ProfileScreen: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
9
10 // Image picker controller delegate allows you to select an image from the camera or the photo library
11 // Navigation controller delegate allows image picker to appear and dissapear like a normal view controller
12
13 @IBOutlet weak var profilePictureImageView: UIImageView! // Image view we want to display the image in
14
15 let imagePicker = UIImagePickerController() // Initialize an image picker view controller type
16
17 override func viewDidLoad() {
18 super.viewDidLoad()
19
20 imagePicker.delegate = self // States that this view controller will also handle the events
21 }
22
23 @IBAction func selectProfilePicture(sender: AnyObject) {
24
25 let imageSourcePicker = UIAlertController(title: "Select Profile Picture", message: "Please select an image picker method", preferredStyle: .ActionSheet) // Initialize action sheet type
26
27 let cameraAction = UIAlertAction(title: "Take a picture", style: .Default, handler: { action in
28 self.pickImage(.Camera) // Presents picker
29 })
30
31 let cameraRoll = UIAlertAction(title: "Choose from camera roll", style: .Default, handler: { action in
32 self.pickImage(.PhotoLibrary) // Presents picker
33 })
34
35 // Add actions
36 imageSourcePicker.addAction(cameraAction)
37 imageSourcePicker.addAction(cameraRoll)
38
39 presentViewController(imageSourcePicker, animated: true, completion: nil)
40
41 }
42
43 func pickImage(sourceType: UIImagePickerControllerSourceType) {
44 imagePicker.allowsEditing = false // Prevent editing
45
46 // Three sources: .PhotoLibrary, .Camera, .SavedPhotosAlbum
47 self.imagePicker.sourceType = sourceType // Type of image selection
48
49 // Presenting image picker view controller on top of stack
50 self.presentViewController(self.imagePicker, animated: true, completion: {
51 print("Opening image picker view controller")
52 })
53 }
54
55
56 // MARK: - UIImagePickerControllerDelegate Methods
57
58 func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
59 if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
60 // If returned a valid image
61 profilePictureImageView.contentMode = .ScaleAspectFit // Set content setting
62 profilePictureImageView.image = pickedImage // Set image
63 }
64
65 // Dismiss the image picker view controller
66 dismissViewControllerAnimated(true, completion: {
67 print("Dismissed image picker view controller")
68 })
69 }
70
71 func imagePickerControllerDidCancel(picker: UIImagePickerController) {
72 // Dismiss the image picker view controller
73 dismissViewControllerAnimated(true, completion: {
74 print("Cancelled: Dismissed image picker view controller")
75 })
76 }
77
78
79}
80
Hope you found this helpful! You can find the source code on GitHub.
Here's another example of two different types of action sheets in case the first example was difficult to grasp.
1Text Input Dialogue:
2// Create text modal for adding an event name prediction
3let newCategoryAlert = UIAlertController(title: "Enter Location", message: "Manually add a location suggestion", preferredStyle: .alert)
4
5// Add text field item
6newCategoryAlert.addTextField { (textField) in
7 textField.text = "" // No placeholder
8 textField.autocapitalizationType = UITextAutocapitalizationType.words // Capitalization rules
9}
10
11// Add cancel action
12newCategoryAlert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil)) // No action if cancelled
13
14// Add submit action
15newCategoryAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak newCategoryAlert] (_) in
16 // Get text field content
17 let textField = newCategoryAlert?.textFields![0] // Force unwrapping because we know it exists
18
19 self.currentCategory.locationFreq[(textField?.text)!] = 0 // New event name frequency entry with frequency of 0
20
21 // Update category data with new markov model
22 DataManager.updateOneCategory(with: self.currentCategory, index: self.selectedIndex)
23
24 // Refresh the table view on this page
25 self.refreshData()
26}))
27
28self.present(newCategoryAlert, animated: true, completion: nil) // Present the alert
29
30// Regular Action Sheet
31let actionSheet = UIAlertController(title: "Reset Predictions", message: "Are you sure you want to reset predictions? This cannot be undone.", preferredStyle: .actionSheet) // Create alert action sheet
32
33// Create actions
34let resetAction: UIAlertAction = UIAlertAction(title: "Reset Predictions", style: .default, handler: { (alert: UIAlertAction!) -> Void in
35 // User pressed reset all predictions
36 print("Reseting predictions")
37 self.currentCategory = Category(name: self.currentCategory.name, eventNameFreq: [ : ], locationFreq: [ : ]) // Reset predictions data
38 DataManager.updateOneCategory(with: self.currentCategory, index: self.selectedIndex)
39})
40let cancelAction: UIAlertAction = UIAlertAction(title: "Cancel", style: .cancel, handler: { (alert: UIAlertAction!) -> Void in
41 // User pressed cancel
42})
43
44// Add actions
45actionSheet.addAction(resetAction)
46actionSheet.addAction(cancelAction)
47
48self.present(actionSheet, animated: true, completion: nil) // Present action sheet to user
49
50
Hope you found this helpful!