Home / iPhone Tips and Tutorials

Implementing the testDrive Method

Create an action for the TestDrive button using Interface Builder, which generates a method stub for you. In this article, it's time to fill that stub with code.

Add the bolded code in Listing-2 to the testDrive: method in RTViewController.m. You also add the stubs for code that you will be adding later so that you can run your program before you are completely finished with the back and forth of the animation.

Listing-2: Updating testDrive: to Move the Car Up the Screen

- (IBAction)testDrive:(id)sender {

  CGPoint center = CGPointMake(car.center.x,
    self.view.frame.origin.y + car.frame.size.height/2);
  [UIView animateWithDuration:3 animations:^ {
      car.center = center;
   }
   completion:^(BOOL finished){
      [self rotate];
   }];
}

- (void)rotate {
}

- (void)returnCar {
}

- (void)continueRotation {
}

Now, run your program, and click or touch the TestDrive button. Your car moves up the screen and you're on your way!

In the testDrive method, you start by creating the coordinate (CGPoint of where you would like the car to end up.

Remember:
A car is just another view.
CGPoint center = CGPointMake(car.center.x,
    self.view.frame.origin.y + car.frame.size.height/2);

You use the center and frame properties primarily for manipulating the view. If you are changing only the position of the view (and not its size), the center property is the preferred way to do so.

CGPointMake is a function that creates a point for you when you specify the y and x coordinates as parameters (you set the car's new center point). You can leave the x coordinate as is. Doing so makes the car drive right up the center of the screen.

car.center.x

Here's the y coordinate:

self.view.frame.origin.y + car.frame.size.height/2)

self.view.frame.origin.y is the top of the view, but if you have the center there, half the car is off the screen. To keep it all on the screen, you add back half the car's height by including car.frame.size.height/2.

Notice adding to the y coordinate because y increases as you move down the screen from the origin.

So, how do you get the sucker to actually move? Use the following code:

[UIView animateWithDuration:3 animations:^ {
  car.center = center;
}

animateWithDuration:animations:completion: is a UIView class method that allows you to set an animation duration and specify what you want animated as well as a completion handler that is called when the animation is complete.

First you specify that you want the animation to take three seconds:

animateWithDuration:3

and then you pass in an animation block with what you want animated:

animations:^ {
  car.center = center;
}

This sets the new center you just computed, taking three seconds to move it from start to finish.

If the preceding syntax seems mysterious (and it probably should), don't worry: explain blocks in the next section.

Although that's all there is to getting the car to move across the screen, you're not done. You want it to rotate and then drive back across the screen and then rotate again. That's where the completion handler comes in.

Although you can use a completion handler to simply let you know that an animation is finished, using a completion handler is the primary way that you link multiple animations.

The completion handler that you specify:

completion:^(BOOL finished){
  [self rotate];
}

causes the rotate message to be sent when the animation is complete. You do the actual rotation in the rotate method.

Of course, right now, the rotate method does nothing. I have you add it so that the app would compile and run. I have you add returnCar and continueRotation to eliminate the Incomplete implementation RTViewContoller.m compiler warning.

animateWithDuration:animations:completion: is only one of a number of block-based methods that offer different levels of configuration for the animation block. The other methods are the following:

animateWithDuration:animations:
animateWithDuration:delay:options:animations:completion

animateWithDuration:animations: has no completion block, as you can see.

Both animateWithDuration:animations:completion: and animateWithDuration:animations: run only once, using an ease-in, ease-out animation curve. If you want to change the default animation parameters, you must use the animateWithDuration:delay:options: animations:completion: method, which lets you customize the following:

  • The delay to use before starting the animation
  • The type of timing curve to use during the animation
  • The number of times the animation should repeat
  • Whether the animation should reverse itself automatically when it reaches the end
  • Whether touch events are delivered to views while the animations are in progress
  • Whether the animation should interrupt any in-progress animations or wait until those are complete before starting

As you probably noticed (and even admitted to) one of the things slid over was an explanation of the animation syntax:

[UIView animateWithDuration:3 animations:^ {
  car.center = center;
}

Animations use blocks. A block is a primary design pattern in the iPhone and is becoming increasingly more important.

So before get to the rotate completion handler, I want to explain blocks.

[Previous] [Contents] [Next]