Friday, June 29, 2012

Interlude 3 - A Fader Class (Updated 17/01/16)

Interlude 3.1 Transition Effects


This Interlude was originally part of Tutorial 4 but we split it out because it is useful from a stand alone perspective and Tutorial 4 was getting too long.

There will be times when your App needs to transition from one screen to another and effects are useful in letting the user know what is happening. The following is one approach to what transition to use and when.
  1. Fade: The content is the same but users change their view of the content (for example, switching between day and week view in a calendar or switching between viewing a list of images and viewing the thumbnails of the same images).
  2. Slide: Users move to an item at the same level in the navigation hierarchy.
  3. Zoom: Users move to an item at a different level in the navigation hierarchy (for example, from a parent item to a child item or a child item to a parent item). Users create a new item, send an item, or save an item.
iOS has a bunch of built in transition effects but unfortunately (to our knowledge) they are not currently available in Codea. We will be using a fade transition in the Splash Screen tutorial, so let's have a look at one way of achieving this.


Interlude 3.2 A Fade Transition Effect


Vega over on the Codea forums has once again done the hard work for us. He produced a class which can fade in or out a screen. We have simplified the code to just fade out a screen but you can see the original class at the link above. Create a new tab in your project and paste in the following code. We will show you how to use it in Tutorial 4.


Fader = class()

function Fader:init(fadeSpeed)

--[[ fadeSpeed determines how quickly the screen fades. 1 is the lowest speed available and will give the slowest fade effect. The bigger the number the faster the fade. The self.fading variable is used to detect whether the class is in the middle of fading something and self.alpha is used to determine the transparency of the rectangle covering the screen. An alpha of zero is transparent, and it can go up to 255 which is solid. ]]

    self.fading = false
    self.alpha = 0
    
    if fadeSpeed > 0 then
        self.fadeSpeed = fadeSpeed --raise this number to fade faster
    else
        self.fadeSpeed = 1
    end
end

function Fader:fade(func)

--[[ func is the function that this class will call once the fade transition is complete (assuming it exists and isn't NIL. The Fader: fade() function is called to start the fading transition. ]]

    self.fading = true
    if func ~= nil then 
        self.func = func 
    else
        print("Warning:: Fader call back method is NIL.")
    end
end

function Fader:draw()

-- If it is time to fade then...

    if self.fading then

-- [[ Do the right thing and save the current screen settings, we will return these at the end using popStyle(). No smooth and no stroke are used to ensure we get an acceptable frame rate. Without these two statements the animation will appear too slow, particularly on an iPad 1. ]]

        pushStyle()                      
        noSmooth()                      
        noStroke()

-- [[ fill is set to black and to the current alpha. Initially alpha will be zero. i.e. transparent and get gradually more solid. As Vega mentions in the comment below, if you want to fade to some other colour then change this fill statement. ]]

        fill(0, 0, 0, self.alpha)
        
        --change that color if you want to fade to a color other than black
        
-- [[ The basic approach is to create a rectangle in the fill colour which covers the entire screen. For our fade out example, the rectangle is initially transparent and gets more solid each draw cycle by the fadeSpeed. Remember the draw() function gets called 60 times a second if possible. ]]

        rect(0,0,WIDTH,HEIGHT)
        popStyle()
        self.alpha = self.alpha + self.fadeSpeed
        
-- [[ The maximum alpha value is 255. This indicates a solid colour and when we reach it the fade is complete. So at this stage self.fading becomes false and the transition end call back function is called (if defined). ]]

        if self.alpha >= 255 then 
            self.alpha = 255 
            self.fading = false --fade complete
            if self.func ~= nil then self.func() end -- its all black, so switch the frame
        end
    end
end