Control iApp behaviors and properties with an XCode animation object

__________________

iApp developers have complete control over the properties and behaviors of both built-in XCode library objects and objects based on custom and derived classes. With CABasicAnimation objects, iApp developers can easily make an iApp come alive through animation of any CALayer property - color, position, opacity, rotation/orientation, etc. However, a direct combination of these tools - a CABasicAnimation of a CALayer that directly controls other class properties within that iApp - becomes more of a challenge. Fortunately, XCode can handle this. I built BSD, an iApp available for sale at iTunes that relies on this idea and to highlight the solution, I built a simple iApp called DV (for Dependent Variables), available as a GitHub repository. Using XCode 5.1 and targeting iOS 7.1, DV has a ViewController class with most of the machinery of the iApp. DV also has the AppDelegate class, and customView, a simple custom class. I did not use the Interface Builder to build DV; the ViewController viewDidLoad method dynamically builds all view controller objects DV needs.

DV has a simple user experience. The first X Position label shows the states of the top two squares; the second X position label reflects the lower square. The Rotation Angle applies to all the squares.

Initialized DV animations
When the user taps START, the top two squares rotate and slide to the right and the lower square rotates and slides to the left.
DV running.
The top square translation / rotation
animations directly control the
location and angle of the
other squares

The top square animations continuously
update the Rotation Angle and first
X Position label values 

The X Position label and Rotation Angle labels continuously update to show the latest instantaneous values. The PAUSE / RESUME button toggles, and when the animations finish, the RESET button enables.
DV animations completed
The button interlocks make intuitive sense to the user.

In Objective C, a class declares its instance variables in the header file @interface section. All class methods can see and change instance variables inside that class. Additionally, properties of methods within that class can take the values of instance variables inside that class. Therefore, if a CABasicAnimation object can change an instance variable of an object, those changes could drive object behavior in other methods through direct property changes of those objects. A CABasicAnimation object cannot change these instance variable values directly, but through a CADisplayLink object - a native Objective C class - a CABasicAnimation object can update these instance variables indirectly. CADisplayLink works as a timer, synchronized to the screen refresh rate. Each time a CADisplayLink object fires, it calls a selector, or specified method. The selector can then update class instance variables. These instance variables then drive changes in objects with properties controlled by those variables. In this way, the animation indirectly controls those objects. Sample iApp DV relies on this engineering. In the XCode simulator, DV is optimized for iPhone Retina (3.5-inch). The main class, ViewController, has a CADisplayLink object which drives changes in objects both in ViewController and in a derived class instance. To show the flexibility of this approach, the changes in the derived class object happen through a direct call to a class method, and through direct updates to a derived class property.

Method viewDidLoad – the last method of class file ViewController.m - builds and configures the fourteen view controller objects of DV, and places each controller object in its own layer. All controls are instances of Xcode base classes, except for thirdView. Method viewDidLoad initializes three flags

(Code 1)
DV application control flags
at lines 533 to 535 that control the toggling, appearance, and enable/disable status of the control "buttons" at the bottom of the simulator screen; we won’t explore the code behind this button behavior because this article does not focus on that engineering. DV launches with the START enabled, and the squares initialized.

The thirdView object created in the viewDidLoad method of ViewController is an instance of the DV customView class. This class derives from the UIView base class. In customView.m, the drawRect method draws and fills a rectangle based on a CGRect parameter. In the customView class, method cGAffineTransforms uses CGAffineTransforms at lines 31 and 32 to translate and rotate the thirdView object, calling the transforms with CGAffineTransformConcat at line 33 to make them combine correctly.

(Code 2)
customView class transforms









To make the transforms occur instantaneously, the animation block sets both animateWithDuration and delay to 0.

The animation objects in ViewController.m method prmrySquareLayerMainAnim only animate the upper square.

(Code 3)
When DV calls this method, the
objects in this method only
animate the upper square.
When the user taps START, the ViewController.m touchesBegan method launches; lines 216 and 217 in this method configure displayLink, the CADisplayLink variable.

(Code 4)
Configure the CADisplayLink
object in touchesBegan
at lines 216 - 217
A CADisplayLink variable is a timer, firing at the screen’s refresh rate. Each time it fires, it calls a selector callback - in this case, method squareLayerStateChange at line 216. Line 221 calls method prmrySquareLayerMainAnim, to start the primary square animations. Each time displayLink calls selector method squareLayerStateChange, this callback updates ViewController instance variables
  • curPos
  • curXVal
  • curRadAngle
based on the latest instantaneous location and rotation angle of prmryAnimView. For DV, prmryAnimView is the UIView parent of the primary square layer - the top square in DV. Method squareLayerStateChange

(Code 5)
Update the labels;
change second and
third square properties
uses the instance variable values
  • curPos
  • curXVal
  • curRadAngle
to update the first two labels of the application (lines 40 - 41). Then it uses the curXVal and curRadAngle values to translate and rotate the second square, secondaryAnimView (lines 52 – 54), with simple CGAffineTransforms. The squareLayerStateChange method also changes properties in the customView object thirdView, created by viewDidLoad at line 513. At line 68, squareLayerStateChange directly updates the thirdView object xPosVal property with curXVal. To rotate the thirdView object, at line 70 the squareLayerStateChange method calls the cGAffineTransforms method of the thirdView object, with parameter curRadAngle.

To show that a derived class method can use the xPosVal property as a transformed value, the customView class cGAffineTransforms method uses

–(self.xPosVal)

as a negative value in a translate transform (see Code 2 above) to move the object to the left.

Although the examples in DV focused on simple animations, the CADisplayLink technique has huge potential. With this approach, a CABasicAnimation can drive changes to any object property that an XCode statement can see – layer color, sound generator frequency, or UILabel font size, for example. It could even control object creation based on animation object values. It has endless possibilities.