• 10 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 04/07/2019

Establish user flow

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

At this point, let’s refer back to our view component. We’ve got plenty of views ready to serve us, however they only exist in isolation. We now need to establish the user flow and implement the navigation between our view controllers (between app screens).

We've implemented the main screen, but how about the image picker? The appearance we've got on our design requirements refers to a special UI element in iOS called "Alert Controller".

Understanding Alert Controller

Alert Controller is represented by the class  UIAlertController . It's designed to present two types of modal interactions: Alert and Action sheet.

Alert is displayed in a form of a dialog. Here's an example of both views:

Alert controller layouts
Alert controller layouts

As demonstrated above, depending on the number of action we are trying to fit in Alert style view, the actions may be listed horizontally or vertically. Action Sheet style view always lists actions vertically.

The contents of both styles, Alert and Action Sheet, consist of following components:

  • Title

  • Message

  • Actions 

The dialogs are the same in function, the only difference is presentation.

When should I use which style? :euh:

Utilization context

Alert style is designed to accommodate fewer options (1 to 3). The options typically refer to a single subject.  This could be messages that require acknowledgement via a single action, or this could be a prompt which asks the user whether to handle a procedure (for example:  OK/Cancel ,  YES/NO  etc) or how to handle a procedure (for example:  Now/Later/Never/Cancel ).

Action sheet, on the other hand, presents different functional options applicable to a specific context. For example:  Edit/Share/Add reaction  or  Take photo/Pick from Library/Random . Do you see where I'm going here? :p

So, how many options is ok to use there? 

As a general rule,  the fewer the better!

Types of actions

As you may notice, the buttons are presented in different styles like plain, red, or bold. Those correspond to the types of actions.

What type of actions can be used? o_O

There are three types of actions:

  • Default - Plain

  • Cancel - Bold

  • Destructive - Red!

Now you know enough to see how this fits our design for implementing the image picking options.

Implementing Image Picker

Can wait no more!
Can't wait any more!

Implementing the flow

The image picking functionality will eventually need to be attached to our creation image. We have to learn a couple more things in order to do that. For the moment, let's borrow the 'Share' button and display the picker when user taps on it. To make the code more organized, we'll create a separate function for it, so that we can place a single line of code (in this case, the code will call that function) anywhere we like, whether it's a share button action or any other trigger:

func displayImagePickingOptions() {
    print("Displaying Image Picking Options")
}

And temporarily call it from the share button action:

@IBAction func share(_ sender: Any) {
    displayImagePickingOptions()
}

Do a quick test, run the app, and click Share button. You should see this in the console:

Displaying Image Picking Options 

Defining Alert Controller

Now let's create the controller. According to our designs, we've got the title "Choose image" but not the message. Well, it's going to be nil then! So let's declare and initialize a variable:

let alertController = UIAlertController(title: "Choose image", message: nil, preferredStyle: .actionSheet)

In the code above, we've got 3 parameters: title, message, and style.

But why is the last one called 'preferredStyle' and not just 'style'? o_O

The reason the last property is called 'preferredStyle' and not just 'style', is due to layout uncertainty.  iOS will do its best to accommodate a requested style, however it will adjust as needed.

Next, we need to add actions: Take photo, Library pick, Random and Cancel. The syntax for creating actions is this:

let action = UIAlertAction(title: String?, style: UIAlertActionStyle) { (<#UIAlertAction#>) in
        // code to handle the action
    }

There's a new element here: the code in curly brackets  at the end. :waw: This is called Closure. Closure is a block of code, like a function.

Closures can be passed block of code to execute upon certain conditions. The condition is defined by the function design. In the case of alert controller actions, the code is to be executed based on the action selected by the user. Closures can also have parameters.  In this example, it's a variable of UIAlertAction type (the action itself will be passed to our block in case we need it). This block is often also called a Handler.

So, let's create our first action:

// create camera action
    let cameraAction = UIAlertAction(title: "Take photo", style: .default) { (action) in
        print("Launching device camera")
    }
    
// add camera action to alert controller
alertController.addAction(cameraAction)

You know what to do now! Your turn! Go ahead and implement the remaining actions:

  • Library pick

  • Random 

  • Cancel

Do your thing!
Do your thing!

Here's my version, yours should be very similar:

// create library action
    let libraryAction = UIAlertAction(title: "Library pick", style: .default) { (action) in
        print("Launching device library")
    }

// add library action to alert controller
alertController.addAction(libraryAction)
        
// create random action
let randomAction = UIAlertAction(title: "Random", style: .default) { (action) in
        print("Picking from local images")
    }

// add random action to alert controller
alertController.addAction(randomAction)
        
// create cancel action
let canceclAction = UIAlertAction(title: "Cancel", style: .cancel) { (action) in
        print("Canceling image picking - doing nothing in fact:)")
    }

// add cancel action to alert controller
alertController.addAction(canceclAction)

In this implementation, we used default styles for all the remaining image picking options and cancel style for the cancel option.

You noticed that we only got to use  .cancel  and  .default  action styles, bit not  .destructive . Thankfully our app is harmless and we won't need to perform any destructive actions, only constructive! :zorro:

The options are ready, so let's show them off by presenting our alert controller:

present(alertController, animated: true) {
    // code to execute after the controller finished presenting
}

present  is a view controller method that presents another view controller - implements the navigation - the screen flow.

Here's the image picker presenting function altogether:

func displayImagePickingOptions() {
        let alertController = UIAlertController(title: "Choose image", message: nil, preferredStyle: .actionSheet)
        
        // create camera action
        let cameraAction = UIAlertAction(title: "Take photo", style: .default) { (action) in
            print("Launching device camera")
        }
        
        // add camera action to alert controller
        alertController.addAction(cameraAction)
        
        // create library action
        let libraryAction = UIAlertAction(title: "Library pick", style: .default) { (action) in
            print("Launching device library")
        }
        
        // add library action to alert controller
        alertController.addAction(libraryAction)
        
        // create random action
        let randomAction = UIAlertAction(title: "Random", style: .default) { (action) in
            print("Picking from local images")
        }
        
        // add random action to alert controller
        alertController.addAction(randomAction)
        
        // create cancel action
        let canceclAction = UIAlertAction(title: "Cancel", style: .cancel) { (action) in
            print("Canceling image picking - doing nothing in fact:)")
        }
        
        // add cancel action to alert controller
        alertController.addAction(canceclAction)
        
        present(alertController, animated: true) {
            // code to execute after the controller finished presenting
        }
    }

Let's quickly test our new implementation. Run the app:

FrameIT Image Picker
FrameIT Image Picker

Click on the Share button and then chose one of the options. You should have this in the console after you've gone though all the options:

Launchingdevicecamera
Launchingdevicelibrary
Pickingfromlocalimages
Cancelingimagepicking-doingnothinginfact:)

Looks as expected!

So, what happens when we click Cancel?

When we click cancel, our alert view controller gets dismissed. Let's explore the navigation functionality (displaying and hiding view controllers) a bit more in detail.

Navigation in iOS

The UIAlertController is a convenient, simple way to present the user with options and let them select further actions. It's provided by Swift SDK and is only intended to be used as is. A bigger limitation is that it supports minimal customization and does not support subclassing.

What if you want to "wow" a user with a fancy picker like this:

Alternative Image Picker
Alternative Image Picker

Basic Navigation

This doesn't look like it can be accommodated with a convenient AlertController. To implement this look, we must design a separate ViewController/Scene in a storyboard and implement a navigation flow by displaying the new view controller instead of a built-in, ready-to-go alert controller.

The good news is that custom view controller follows the same navigational rules as alert controller. :zorro:

Let's imagine we have another view controller in our storyboard. It would have a dedicated Swift file associated with it and a storyboard ID:

Storyboard view controller identity
Storyboard view controller identity configuration

Presenting a view controller

To present a view controller, let's first declare and initialize it. For this type, we do this by accessing storyboard, which requires using the storyboard ID:

let viewController:UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ImaginaryViewControllerID") as UIViewController

The actual presenting part is already familiar to you, because it's exactly the same as for alert controller:

present(viewController, animated: false, completion: nil)
Dismissing a view controller

In case of custom view controllers, there's no default Cancel button (action) that's provided to us, so we must implement both the button and the code. Here's the code:

dismiss(animated: true, completion: nil)
Passing data to a child view controller

One of the common ways to pass data to a child controller is by assigning suitable properties in the child controller before displaying it. For example, say, we needed to pass an image to a child controller. We could declare an image property in our imaginary view controller:

class ImaginaryViewController: UIViewController {
    var imageProperty: UIImage
    
    ...
}

And then, assign the value to that property from parent view controller before presenting the imaginary one:

viewController.imageProperty = imageToPass

Ok, good to know how to pass data to the child view controller. How about receiving some back? :euh:

Passing some data back FROM a child controller to parent is a bit more sophisticated than passing the data TO a child controller. There are various approaches available which are suitable for different purposes. You'll learn them soon enough! :ange: We will, however, take a sneak peek at one of the options in the next chapter.

Advanced Navigation

It's not always that we can present a simple view controller to accommodate various app requirements. iOS presents a variety of navigational options:

  • Navigation controller

  • Page Controller

  • Tab Navigation 

  • ... etc.

Depending on design requirements you will be using different controllers on different occasions.  These could be individual controllers or their combinations - they can be nested just like subviews within views.

We'll save that for the following course! :p

Let's Recap!

  • AlertController is used to present dialogs of 2 styles: Alert and ActionSheet

  • AlertController is represented by the  UIAlertController  class which is a subclass of  UIViewController  .

  • AlertController is intended to be used as is, it cannot be subclassed, and seldom can be customized.

  • Any other view controller can be presented in a way similar to alert controller

  • Custom view controllers must be present and dismissed.

  • Special navigational elements are used to implement advanced navigation techniques, such as Navigation Controller.

Exemple de certificat de réussite
Exemple de certificat de réussite