Chapter 23
Pulling It All Together

Estimated Time


This chapter weaves the components we’ve created into a nice, unified app and user experience.

To recap, we have created the following things:

  1. An infinite scrollview subclass of UIScrollview
  2. An Astrological Sign Provider that stores data about the various signs
  3. A Stars background that has 8 different layers of scrolling content
  4. A great looking radial menu with complex animations and a nice interaction mechanism that uses long presses
  5. An info panel that links to the C4 site

Now, to bring COSMOS to life, we need to address the following:

  1. Add the menu, background and info panel to the app
  2. Link the menu to the background via a selection action and the background’s goTo method
  3. Link the menu to the info panel via an info action
  4. Add a couple of ambient audio files that will provide background music for the app

So, let’s get to it.

The WorkSpace

Most of the work we’re going to be doing is centered around the WorkSpace. Although we’ll have to tweak a couple of classes, it’s the WorkSpace’s setup() where we will be creating objects and linking them together.

First, if you’ve been using the WorkSpace to launch or test any of the work you’ve been doing, now’s the time to clean it up and change the background color to COSMOSbkgd.

It should look like this:

1
2
3
4
5
6
7
8
9
10
let COSMOSprpl = Color(red:0.565, green: 0.075, blue: 0.996, alpha: 1.0)
let COSMOSblue = Color(red: 0.094, green: 0.271, blue: 1.0, alpha: 1.0)
let COSMOSbkgd = Color(red: 0.078, green: 0.118, blue: 0.306, alpha: 1.0)

class WorkSpace: CanvasController {

    override func setup() {
        canvas.backgroundColor = COSMOSbkgd
    }
}

Stars

Adding the stars background is dead-easy, just create a copy of Stars and add it to the canvas, like this:

1
2
3
4
5
6
7
class WorkSpace: CanvasController {
    let stars = Stars()
    override func setup() {
        canvas.backgroundColor = COSMOSbkgd
        canvas.add(stars.canvas)  
    }
}

Done. Run it and you’ll be able to scroll through the COSMOS.

Adding the menu is pretty easy too. Just follow the same steps as above, and add the menu after you’ve added the background.

1
2
3
4
5
6
7
8
9
10
class WorkSpace: CanvasController {
    let stars = Stars()
    let menu = Menu()
    override func setup() {
        canvas.backgroundColor = COSMOSbkgd
        canvas.add(stars.canvas)  
        menu.canvas.center = canvas.center  
        canvas.add(menu.canvas) 
    }
}

The Menu’s Frame (Explained)

We want the behaviour of the menu to be like this: The menu should open only when the user presses on it, i.e. not anywhere else on the screen. This is why we make the canvas small (i.e. 80x80). Since the frame is this small the interaction with the menu’s canvas is limited only to this 80x80 view.

Simple.

Info Panel

This step’s a cinch. Create another variable for the info panel, then instantiate it in setup() and add it to the WorkSpace’s canvas after you’ve added the menu.

Then, go into InfoPanel.swift and add the following line to it’s setup():

1
self.canvas.opacity = 0.0

Since the opacity is 0.0 the canvas automatically will not receive touches, so adding it over top of the menu is okay at this point and will not prevent the user from touching the menu

Your WorkSpace should look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class WorkSpace: CanvasController {
    let stars = Stars()
    let menu = Menu()
    let info = InfoPanel()

    override func setup() {
        canvas.backgroundColor = COSMOSbkgd

        canvas.add(stars.canvas)

        menu.canvas.center = canvas.center
        canvas.add(menu.canvas)

        canvas.add(info.canvas)
    }
}

Connect the Menu & Background

To connect the menu and background we’re going to use a nice little trick: we’ll add a special type of action to the menu and link that with the background’s goTo() method.

Go into Menu.Swift and at the very top of the file, above the class declaration, add the following line:

1
typealias SelectionAction = (selection: Int) -> Void

This is a type alias through which we’ll be able to assign a method from another class. The selection action is essentially the action to which we want to send the menu’s current selection.

Create a variable to hold reference to a selection action:

1
var selectionAction : SelectionAction?

Navigate down to createGesture() and in the case .Cancelled: block add the following:

1
2
3
if let sa = self.selectionAction  where self.menuSelector.currentSelection >= 0 {
    sa(selection: self.menuSelector.currentSelection)
}

Since we sometimes set the current selection to -1, we need the additional where statement

Remember this method from Chapter 14?:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func goto(selection: Int) {
    let target = canvas.width * Double(gapBetweenSigns) * Double(selection)

    let anim = ViewAnimation(duration: 3.0) { () -> Void in
        self.bigStars.contentOffset = CGPoint(x: CGFloat(target),y: 0)
    }
    anim.curve = .EaseOut
    anim.addCompletionObserver { () -> Void in
        self.signLines.revealCurrentSignLines()
    }
    anim.animate()
    
    signLines.currentIndex = selection
}

This method conforms to the same parameters as the SelectionAction type alias we just created. It also takes an integer and figures out a target and animates to that point in its scrollview.

Finally, go to your project’s WorkSpace, and add the following line:

1
menu.selectionAction = stars.goto

Your WorkSpace should look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class WorkSpace: CanvasController {
    var background : ParallaxBackground?
    var menu : Menu?
    var info : InfoPanel?

    override func setup() {
        canvas.backgroundColor = COSMOSbkgd

        background = ParallaxBackground()
        canvas.add(background?.canvas)

        menu = Menu()
        menu?.canvas.center = canvas.center
        canvas.add(menu?.canvas)

        info = InfoPanel()
        canvas.add(info?.canvas)

        menu?.selectionAction = background?.goto
    }
}

Run it and things should work like this for you:

The process for linking the menu and info panel is almost identical to the previous step.

In Menu.Swift and at the very top of the file, above the class declaration, add the following line:

1
typealias InfoAction = () -> Void

Also, in Menu.swift add the following class variable:

1
var infoAction : InfoAction?

Then, scroll down to the .Cancelled section of the menu’s gesture and add the following condition:

1
2
3
4
5
6
7
8
if let ib = self.menuSelector.infoButton {
    if ib.hitTest(center, from: self.canvas),
        let ia = self.infoAction {
            delay(0.75) {
                ia()
            }
    }
}

Finally, go back to your project’s WorkSpace and add the following line:

1
menu.infoAction = info.show

Run it, and you should see this:

Ambient Audio

There are two files that should be included in your project. We’re going to play as soon as the application launches.

In the your project’s WorkSpace, create the following two class variables:

1
2
let audio1 = AudioPlayer("audio1.mp3")!
let audio2 = AudioPlayer("audio2.mp3")!

Then in setup(), loop and play them like so:

1
2
3
4
5
audio1.loops = true
audio1.play()

audio2.loops = true
audio2.play()

Now things are sounding stellar.

Initial Stars Offset

We prefer the stars to start offset from any particular constellation. So, open Stars.swift and add the following line to the end of setup():

1
bigStars.contentOffset = CGPointMake(view.frame.size.width * CGFloat(gapBetweenSigns / 2.0), 0) 

The Last Touch

If you haven’t already done so, now’s the time to update a couple of simple deployment settings.

Click on the COSMOS project at the top of the project navigator in Xcode. Then under the General tab, navigate down to the Deployment Info section. Choose the following settings:

  • Portrait: selected
  • Upside Down: selected
  • Landscape left: unselected
  • Landscape right: unselected
  • Hide Status Bar: selected
  • Requires Full Screen: selected

AAAAAAAAND

WE.

ARE.

DONE.