Flow + iOS Gestures

In this tutorial you’ll learn how to integrate 3 timelines from Flow into an iOS app and trigger each one using a gesture.

First…

Grab the Flow File

And, if you want to jump straight to the end…

Grab the Final Xcode Project

Intro

We’re starting this tutorial with a premade Flow file that has 3 timelines, each using the same starting shape.

This is that the Flow file looks like.

The idea with this tutorial is two-fold:

  1. To show you how to trigger timelines using gestures in iOS
  2. To show you that you can apply multiple timelines to the same starting view.

Let’s say you wanted two different effects for an icon, or a button, depending on how you interact with it… The second point above is the basis for applying different timelines to the same object.

Here are the three timelines, side-by-side, that we'll be working with. All start from the same shape.

Export Code

This will be the only touchpoint with Flow during this tutorial. With the gestureTimelines.flow file open.

  1. Press CMD+SHIFT+E to open the Export Code window.
  2. Select all three timelines
  3. Select iOS (only) as a the project type
  4. Hit Export

Export all three timelines to iOS.

Xcode

From now on we’re going to be working in Xcode.

Create A Project

We’re going to be creating a new iOS project, instead of modifying an exported one.

From the Xcode welcome window…

  1. Create a New iOS Project
  2. Choose Single View App
  3. Name the project FlowGestures
  4. Save it.

Create a new Single View project.

No need to include tests.

At this point, our project is a simple iOS app that launches with a white background.

Import Flow Common

To integrate with iOS / Swift, Flow generates a few simple files that handle animation, timelines and styling. Since we have a created a project from scratch, we’ll need to import them into our project.

  1. Open the Shrink.xcodeproj file
  2. Select all the files in the Flow Common folder (from the project navigator on the left)
  3. Drag the files into the empty FlowGestures.xcodeproj file and make sure to choose the “Copy if needed” option.

The Shrink project is in the folder that was just generated by Flow.

Drag all the common files into your new project.

That’s it. The basis for the project is in place. Let’s move on to the good stuff.

A SceneView & A Timeline

The first thing to do is bring in a SceneView. What you would call in Sketch an Artboard, in Flow we call a Scene. When you export a scene to Swift it wraps it up as an extension of the standard iOS UIView.

Since we’re using the same starting elements in our each of our timelines, we’ll only need to bring in one SceneView.

At the same time, we can bring in the ShrinkTimeline.swift file. This timeline is a set of animation commands that can be applied to the SceneView.

Let’s do these steps now.

  1. From Shrink.xcodeproj select SceneView.swift and ShrinkTimeline.swift
  2. Drag the files into your new project.

The sceneview and timeline are in the new project. Also, notice that I grouped all the common files into a folder.

Setup the SceneView

Let’s get that SceneView visible in the app with a tiny bit of code.

Add 3 Variables

From the Xcode project navigator…

  1. Select ViewController.swift
  2. Add the following 3 variables to the view controller…
1
2
3
4
5
6
7
8
//since we created 3 timelines from the same project, we can use a single scene
let scene = SceneView(frame: CGRect(origin: CGPoint.zero, size: SceneView.Defaults.size))

//a reference to whichever timeline is currently being run
var currentTimeline: Timeline?

//a flag to determine if the current timeline should be reset
var shouldReset = false

The scene is our scene view.

The currentTimeline is an optional variable that we’ll use to keep track of the state of our timeline.

The shouldReset is a boolean we’ll use to trigger resetting or playing.

Your code should look like this:

Three variables in your view controller.

Add the Scene

Next, we add our scene so its visible when we run the app.

  1. In the viewDidLoad method add the following code.
  2. Hit run (i.e. the play button in Xcode)
1
2
3
4
5
//add the scene to the app's main view
view.addSubview(scene)

//center the scene to the app's main view
scene.center = view.center

Your code should look like this (just behind the simulator):

The setup scene code is visible just behind the simulator.

That’s it. We’re good to move onto the next step… Integrating our first gesture!

Tap to Shrink

We’re going to add our first gesture, a tap, which will trigger the shrink timeline. To do this, we’ll need to add 3 methods and a bit of setup code.

Reset()

Our goal is to run animations. But, we don’t want to only run them one time! To reset them after they’ve completed, we can use this method:

1
2
3
4
5
//resets the current timeline
func reset() {
    currentTimeline?.reset()
    shouldReset = false
}
  1. Add that code below the viewDidLoad() method.

AnimateShrink()

The first method will take care of setting the shrink timeline to currentTimeline and running its animation. It looks like this:

1
2
3
4
5
6
//runs the shrink timeline
func animateShrink() {
    currentTimeline = ShrinkTimeline(view: scene)
    currentTimeline?.animate()
    shouldReset = true
}
  1. Add that code below the reset() method.

Shrink()

The next method will take care of resetting the current timeline, then triggering its animation. It looks like this:

1
2
3
4
5
//shrink or reset
@objc func shrink() {
    if shouldReset { reset() }
    else { animateShrink() }
}
  1. Add that code below the AnimateShrink() method.

Add the Tap

To trigger the animation, let’s add a tap gesture to the scene view with the following code:

1
2
3
//add a tap gesture to the scene, passing in the shrink method
let tap = UITapGestureRecognizer(target: self, action: #selector(shrink))
scene.addGestureRecognizer(tap)
  1. Put that code inside and at the bottom of viewDidLoad().
  2. Run the app.
  3. TAP THE SCENE!!!!@!#@!@#!~

Your code should now look like this:

Three fancy methods and a tap gesture.

Swipe to Move

Let’s add a swipe gesture to trigger a second timeline on the same object.

Import Timeline

We need to bring in the timeline file from our second project.

  1. Open ShrinkMove.xcodeproj
  2. Drag ShrinkMoveTimeline.swift into our project

Code

Following the exact same pattern as we did for the Shrink timeline, we’re going to create a few methods to handle the Move timeline.

We only need to add two methods this time (the reset() was already added in the last section)

  1. Add the following code underneath the shrink() method in ViewController.swift
1
2
3
4
5
6
7
8
9
10
11
12
//runs the move timeline
func animateMove() {
    currentTimeline = ShrinkMoveTimeline(view: scene)
    currentTimeline?.animate()
    shouldReset = true
}

//move or reset
@objc func move() {
    if shouldReset { reset() }
    else { animateMove() }
}

After that…

  1. Add the following gesture code at the bottom of viewDidLoad()
1
2
3
//add a swipe gesture to the scene, passing in the swipe method
let swipe = UISwipeGestureRecognizer(target: self, action: #selector(move))
scene.addGestureRecognizer(swipe)

Your code should look like this:

Two gestures and a bunch of methods.

Double Tap to Rotate

Our final step is to bring in a third timeline, add a double-tap gesture and the code to handle the rotate animation. Same steps as before…

Import Timeline

We need to bring in the timeline file from our third project.

  1. Open ShrinkRotate.xcodeproj
  2. Drag ShrinkRotateTimeline.swift into our project

Code

Following the exact same pattern again…

We only need to add two methods this time (the reset() was already added in the last section)

  1. Add the following code underneath the shrink() method in ViewController.swift
1
2
3
4
5
6
7
8
9
10
11
12
//runs the rotate timeline
func animateRotate() {
    currentTimeline = ShrinkRotateTimeline(view: scene)
    currentTimeline?.animate()
    shouldReset = true
}

//rotate or reset
@objc func rotate() {
    if shouldReset { reset() }
    else { animateRotate() }
}

After that…

  1. Add the following gesture code at the bottom of viewDidLoad()
1
2
3
//add a swipe gesture to the scene, passing in the swipe method
let swipe = UISwipeGestureRecognizer(target: self, action: #selector(move))
scene.addGestureRecognizer(swipe)

Your code should look like this:

Two gestures and a bunch of methods.

  1. Add the following code underneath the move() method:
1
2
3
4
let doubleTap = UITapGestureRecognizer(target: self, action: #selector(rotate))
scene.addGestureRecognizer(doubleTap)
doubleTap.numberOfTapsRequired = 2
tap.require(toFail: doubleTap)

The last two lines set the gesture up to use 2 taps, and then tells our tap gesture to wait to see if a double tap happens before triggering.

Your code should look like this:

I just squeaked all the rotate code into a single view.

RUN IT!

Run the app in the simulator and have fun trying to do the swipe gesture with your mouse. If you have an Apple Developer account, you can toss the app onto your iPhone and see it running there!

❤︎

background Made with Flow.
underscore Made with Flow.
line2 Made with Flow.
line1 Made with Flow.
circle Made with Flow.
hit Made with Flow.

result(s) found for “”.