Chapter 5

Touches

Here in our fifth app, we take a giant leap forward and really program some code. I want to say this right now: even though this is a big leap forward, there is always an easy ways out. Yes, I want you to do your very best to type in the all the code as you diligently follow the steps. Yes, I even want you to carry on when you feel like giving up; however, at this point, I want to clarify something with you, as I do with my students.

Redefining “Giving Up”

We need to talk about this for one page and I want you to read through this—you will probably need to in order to prepare yourself for this chapter. In the past, you may have associated “giving up” with totally relinquishing a dream you had. So let me share with you my outlook on three terms: “giving up,” “dreams,” and “goals”. I want to talk about these terms in the context of the following four points:

  • A person can have a dream until the day he or she dies. For example, one could dream of being a supernova geek who programs phenomenal multi-million dollar apps. A person could have that dream until the day he or she dies, even if he or she had never even touched an iPhone or knew what the word “Xcode” meant. This is because the equation that makes up a dream has no element of time.
  • A goal, however, is simply a dream with an added element of time. Think about it. When the element of time in your goal's equation runs out, you FAIL! It's really simple. If you plan to become a supernova geek and sell a million apps within 12 months and you cannot compile “hello world” after 12 months, then you've FAILED!
  • The more we accomplish goals within our time constraints, the more confident we become. That's why a good professor sets baby steps along the way to ensure that his or her students accomplish goals and feel really good about themselves. That's why good professors make little programs that move students a little closer to their ultimate goals. Each week, my students need to finish a set goal by programming an app. If they do not send me that completed app within the time limit, I fail them for that assignment! However, this is rare because rather than give up when it gets really hard, I have some back up angels that help my students succeed and meet their goals in time.
  • Rather than give up when the going gets tough, you can
    • First, watch me program this code in the video at http://bit.ly/qp6aCS and simply follow along. I go a little fast to keep the video short, but you can always pause it. In June 2011, the average person paused the video 28.5 times (all viewers). The average student of mine paused the video 11.3 times.
    • Secondly, if watching the video does not result in total success, you can download my code for this program at http://bit.ly/r1isYn. Here, you can visually compare your code with mine. I tell students to try visually comparing first; if that doesn't work, I have them paste my code into either Pages or Word, and then paste their code into another similar document. After this, they should GO AWAY from their computers and check my code line by line against theirs.
    • Thirdly, if the preceding steps don't work, I don't want you to give up! I want you to paste my code into your code after you have dragged your icons from the nib file into your header file. This means that you still do steps 1 through to 30, which involve mostly dragging and dropping. Then, paste the implementation code into your implementation. When it compiles, I want you to then try it again on your own before moving on to the next chapter.

The preceding steps eliminate the possibility of you giving up on being a supernova geek. I LOVE receiving emails from students and readers telling me how proud they are of being geeks, and how they cannot believe that so many people are downloading and buying their apps. I especially love it when they tell me that they never programmed before in their lives, and how this book showed them they could program apps and not give up. A wife and mother of four in Helena, Montana brought me to tears when she told me that when her husband lost his job as a boiler maker, she bought my book and never gave up—she supported her family for over a year until her husband found another job. She still programs and sells apps.

Essentially, first and foremost, try your hardest to do it by just reading the chapter. If it's too much for you, then check out the video. If the video does not help, then download the code, move away from your computer, and check your code visually, line by line. As a last resort, you can paste my code into yours after you drag-and-drop the other elements into your code.

OK—let's do it.

Roadmap Recap

Going back to the car mechanic analogy, we understand that nowadays, as mentioned in the previous chapter, car mechanics are very specialized: only a handful know how to completely strip down and rebuild a specific car. So far, we have been peering over the shoulder of one such car mechanic, as he has changed and swapped specific components inside the engine. Today, you will build a very basic lawnmower engine. It will involve more steps than you've had to take thus far, but at the end of this chapter, you will have taken a huge leap forward.

As you build your lawnmower engine, there will be times that you look down and see a bigger mess of tools, nuts, and bolts than you have ever seen before. But hang in there. Follow me as I ask you to stand up from time to time and look at that “mess” from my point of view, not yours, and it will all make sense to you.

Touches: A View-Based Application

The touches app initially looks like the cover of this book. The lulu fruit however, can be moved around with your fingertips after you touch it. There are also three buttons on the top called Shrink, Move, and Change. The Shrink button is a special button; after you press it, the lulu fruit icon shrinks and the text inside the button automatically changes to Grow. Upon pressing the Grow button that used to be the Shrink button, the lulu fruit grows back to its original size. If you like, you can quickly have a look at Figures 5–45, 5–46, and 5–47. You can also see the app working right at the beginning of the video here: http://bit.ly/qp6aCS. Only look at the app working though—don't follow the video through the code, as I want to explain the code to you in a specific way.

CGAffineTransform Structs

We will also be working on animation code that the clever people at Apple wrote into a bundle called a data structure. This is a critical tool coders use to perform animations of their objects. The data structure can shrink an object, change its angle, move it, tilt it, and make it do all sorts of other cool animations. All the code that Apple uses to perform these animations is kept in vaults located in core animation data structures called structs. Apple explains this by saying that the “CGAffineTransform data structure represents a matrix used for affine transformations.” Huh? What does that mean? It means that the CGAffine transforms all the critical points of an object you want to animate into a property called a transform. This property is simply a matrix. Once the object you want to animate is in this matrix, CGAffine is able to obey us when we instruct it to change our object's position, angle, shape, scale, and so on. This is what we'll do to the lulu fruit icon.

images

Figure 5–1. The five background images and two lulu fruit icons downloaded from the repository

1. Do I even need to say this ? Close all programs, delete all trash, and drag all your important files and folders to a proper destination so that you have a perfectly clean desktop. Download the images from http://bit.ly/prqKsL and upon unzipping the downloaded file, you will see seven images on your desktop. The five background images are various versions of the cover of this book. The first image will be the upper left-hand one in Figure 5–1, which is a picture of the front of the book without the lulu fruit icon. One can see that the lulu fruit icon is separate from the background pictures. The larger lulu fruit icon is the one that will be on the user screen and will be animated via the CGAffineTransforms we impose upon it. The smaller lulu fruit icon is the icon.png version. Our Change button will scroll through all five background images. The Shrink button and Move buttons will use CGAffine structs to animate the lulu fruit icon.

NOTE: You can of course use your own images and icons. However, this is a long chapter even without spending resources on creating your own images. In class I tell students to hand in this homework assignment using my icons first. Later, they can use their own and if done on time (within three days), they can hand in their homework again with their own icons for extra credit. No students have done this yet.

images

Figure 5–2. The seven images opened on your desktop, ready to launch into Xcode

2. Your desktop should look similar to mine, as shown in Figure 5–2, with nothing but the seven icons and your Mac hard drive on your desktop. Once everything is clean and your images are stacked up and ready to go, YOU are ready to blast off!

images

Figure 5–3. Enter imagesimagesN. Xcode 4.2 provides the option for a Single-View Application, which is the same as the older versions of View-Based Application.

3. Like we have done before, launch Xcode and open a new project by using your keyboard shortcut imagesimagesN. When you see the New Project wizard as depicted in Figure 5–5, you will want to click the Single View Application template.

Once your New Project Window has opened and you have selected the Single View Application, I want you to press return (“Enter”), or click the Next button.

images

Figure 5–4. Call your project “touches.”

4. Call your project “touches,” and most importantly, remember to deselect the “Use Storyboard” option. Once the project is correctly named and the storyboard option is deselected, as shown in Figure 5–4, press Return or click Next.

images

Figure 5–5. Select the option to save your project to your desktop.

5. Save your project to your desktop. You can probably guess by now that we make sure that our current project is located on the desktop. After we're done with it, we place it an appropriate folder.

images

Figure 5–6. Drag your images over to your Supporting Files folder.

6. Initially, when Xcode instantiates itself, it will create a large window that nearly covers your entire desktop. Grab the bottom right-hand corner and shrink the window just enough to see the seven images you downloaded from the repository at http://www.rorylewis.com. As illustrated in Figure 5–6, drag all your images over into your Supporting Files folder in Xcode.

images

Figure 5–7. Check the “Copy items into the destination group's folder …” box.

7. After dropping the image into the Resources folder, you will be prompted to define whether the image will always be associated with its position on your desktop or embedded with the code and carried along with the application file, as shown in Figure 5–7. We want it to be embedded, of course, so click the “Copy items into destination group's folder …” box. Also, check the “Create groups for any added folders” box. Then, click “Finish” (or press Enter).

images

Figure 5–8. Drag your images into the trash.

8. After you have dumped all your images into Xcode appropriately, there is really no need to keep them on your desktop or save them anywhere else. If you want to use them again in another version or if this run through does not work, simply open up the touches folder and they will all be there. There is no need to duplicate the images. So go ahead and trash the images that remain on your desktop, as shown in Figure 5–8.

images

Figure 5–9. Let's make your icon first.

9. First, let's make the icon. Open up your plist while you are in the Supporting Files folder and enter “icon.png” into the icon name, as shown in Figure 5–9. It's not a bad habit to immediately connect your icon into the plist right after dropping in all your images. Once you leave this folder, you might forget to do it later.

images

Figure 5–10. Click on your nib file, open up the Utilities View, and close the Navigator View.

10. Once you have associated your icon with icon.png or the name of your personal icon (if you named it differently), I want you to open your touchesViewControllernib file, as shown in Figure 5–10. As we have done before, we need more space, so let's also open the Utilities View, so we can see the tools and icons we need to dress up the View design area. Secondly, close the Navigator View, because for now, we do not need it.

images

Figure 5–11. Drag a UIImageView onto your View design area.

11. With your Utilities pane open, drag a UIImageView onto your View design area, as shown in Figure 5–11. The UIImageView will hold the current backgrounds you downloaded named WallPaper_01 to wallPaper_05. Later, I will explain how you will write code that will determine which of the five background images will be housed on this UIImageView at any particular point in time. But we do know that the Change button will fire up the code that will switch the background. So, you can guess that the next thing we need to do is drag some buttons onto the view design area.

NOTE: Xcoders also call the View design area the View screen and View frame. So, whether a person says “View design area, View screen, or “View frame, all these terms mean the same thing. I purposefully use the three terms interchangeably throughout this book.

images

Figure 5–12. Drag three buttons onto your View design area.

12. As shown in Figure 5–12, start dragging three buttons onto the top of your View frame. Keep them in line with one another. Keep the outer two buttons lined up with the outer margins and keep the center button centered on the screen. The blue indicator lines will tell you when you move your button close to the range of each of the respective boundaries.

images

Figure 5–13. Name your three buttons Shrink, Move, and Change.

13. Once you have positioned your three buttons onto your View frame, click the buttons and name them. Name them Shrink, Move, and Change, as illustrated in Figure 5–13.

images

Figure 5–14. Drag a second UIImageView onto your View design area.

14. We now need another UIImageView to hold the lulu fruit icon that we can move around with our finger, scale with a button, and move with a button, so add another UIImageView onto your View frame, as shown in Figure 5–14.

images

Figure 5–15. Associate the lulu fruit icon with the second UIImageView.

15. With the second UIImageView selected, go to the image drop- down menu in the Attributes dialogue in your Utilities pane, as shown in Figure 5–15. Select the luluIcon.png to associate it with your second UIImageView.

images

Figure 5–16. Size and locate the luluIcon.png.

16. Once the luluIcon.png appears inside the second UIImageView, I want you to leave the Attributes dialogue in your Utilities pane and click the Size inspector (imagesimages5 ); make the width of the lulu icon a square consisting of 112 × 112 pixels. Also, set the y-axis height to be 137 pixels down from the top of the View pane. You can either center the icon manually (as I do) or do it in the x-axis box. This is illustrated in Figure 5–16.

images

Figure 5–17. Click the Assistant to bring up your touchesViewController header file.

17. We have completed dragging and positioning all the items necessary onto your nib. Now we need to connect these items to your code, as we have done before. We need to work on the touchesViewController header file. Click the Assistant button and your screen will look similar to what is shown in Figure 5–17.

images

Figure 5–18. Reposition your screen so you can work on the header file.

18. There are potentially two things here. First, depending on how large your screen is, you may have to resize or position your View pane inside the nib so that you can see all three of your buttons. Secondly, add curly brackets to the @property directive, as illustrated in Figure 5–18.

NOTE: If you are in Version 4.0 or earlier, you will not need to add squiggly brackets to your @interface directive, as they are automatically instantiated However, if you are using a higher, more recent version of Xcode, then you will probably have to add the squiggly brackets, as shown in Figure 5–18.

images

Figure 5–19. Control-drag a connection from your icon in Interface Builder into your header file.

19. Typically, in the past, when we reached this juncture, I instructed you to just blindly start control-dragging outlets and action into your @directive. Today, however, we will first think about what we're going to do, so we can fuse synapses in your brain to understand how to create a robust header file. To recap what you have done in the past, I fed you a ration of Outlets and actions using the following very broad criteria:

  • Outlets to connect nib file members with your UIImageViews code, which the clever people at Apple wrote for us
  • Actions to connect your buttons with code we wrote in the implementation file

Now, we are going to grow up and move on. Remember how I mentioned that when we click the Shrink button, it shrinks the lulu fruit icon and the text inside it changes to Grow; then when we press the button again, it makes it grow? Well, we need to use the code the folks at Apple wrote that allows us to do cool things like change the colors, text, and other appearances inside a button.

NOTE: This code provided by Apple is located in a class called UIButton. When we use this code, we say we are using an instance of UIButton. In short, we need an outlet for our Change button, so we can change the text in it to go from Shrink to Grow.

We will, of course, also need an outlet for the lulu fruit icon and the background that will hold whatever WallPaper_0x.png is being used. So, we will need three outlets. After we have correctly control-dragged our three outlets into the @properties directive, it will look something like this:

IBOutlet UIImageView *some variable name;
IBOutlet UIImageView *some variable name;
IBOutlet UIButton *some variable name;

Yup! We need to give each of these outlets variable names. Let's use myIcon for the icon, myBackground for the background, and shrinkButton for the button that shrinks the lulu fruit icon. You could use different names, but do that later. Follow along with me now and it will look like this:

IBOutlet UIImageView *myIcon;
IBOutlet UIImageView *myBackground;
IBOutlet UIButton *shrinkButton;

Insofar as the actions for the three buttons are concerned, they stay the same. We will still have three actions for our three buttons sitting right after and outside of the @properties directive, and the code will look something like this:

- (IBAction)some variable name:(id)sender;
- (IBAction)some variable name:(id)sender;
- (IBAction)some variable name:(id)sender;

Yup! We need to give each of these actions variable names. Let's use shrink for the Shrink button, move for the Move button, and change for the Change button. Again, you could use different variable names here, but for now just follow along with me. It will look like this:

- (IBAction)shrink:(id)sender;
- (IBAction)move:(id)sender;
- (IBAction)change:(id)sender;

OK! So let's get to it! Start off by control-dragging from your icon to the @properties directive, as illustrated in Figure 5–19.

NOTE: You may have noticed that sometimes I say “Control-drag a connection from ____ in Interface Builder into your header file,” and other times I say “Control-drag a connection from _____ in Interface Builder into your @property directive.” This is not to confuse you; it's to let you know that they mean the same thing and you may work for, hire, or meet people who use one or the other in their nomenclature.

images

Figure 5–20. Keep the icon as an outlet and name it “myIcon.”

20. As depicted in Figure 5–20, when you reel the fishing line into your @property, keep it as an outlet and name it myIcon.

images

Figure 5–21. Control-drag a connection from anywhere on the Background into the @property directive.

21. Now, we need to connect the UIImageView we dragged into View Design Area with the header file's @property directive, as depicted in Figure 5–21.

images

Figure 5–22. Keep the icon as an outlet and name it “myBackground.”

22. As depicted in Figure 5–22, when you reel the fishing line into your @property, keep it as an outlet and name it myBackground.

images

Figure 5–23. Control-drag a connection from your Shrink button in Interface Builder into your header file.

23. As shown in Figure 5–23, after clicking the Shrink button in your Interface Builder once, control-drag into your header file, in-between the squiggly brackets of the @interface directive. We have discussed in §19 why we are, for the first time, connecting a button to the @property directive. If you skipped that section, I strongly suggest you fully understand why we are connecting a button as an outlet.

images

Figure 5–24. Keep the button as an outlet and name it shrinkButton.

24. As shown in Figure 5–24, when you've control-dragged out to the @interface directive, drop it in by letting go of your mouse and naming it shrinkButton—leave it as an outlet.

Coding the Header File

After we understand that we've connected our outlets we would typically leave the @interface directive, go outside of it, and connect our buttons as actions. In this case, we need to do something we've never done before: set up a few more variables and pointers. We will not go too deep into them, but I will emphasize why we need to do this.

We need to keep track of our images. Specifically we need to

  • Keep track of the current image being displayed in the background. Remember we have five of them, so we'll call the current background currentBackground.
  • We have to store these 5 background images somewhere. The typical way we do this is store all five images in a list we call an array. This means we will need to create an array. Let's call our array bgArray.
  • We also need to know if the Shrink and Move buttons have been pressed because that will change the state. This is explained in detail later, but for now, the location and size of the icon changes and this affects what can be done to it next. So, we'll need to track two button states: the state of the Shrink button and the state of the Move button. Let's call them hasShrunk and hasMoved.
  • Remember when I spoke about how we will use the CGAffineTransform class to help us manipulate our icon (see the “CGAffineTransform structs” section)? Well, we need to use the CGAffineTransform class to first move the lulu fruit icon when we press the move button, and then change the size of the lulu fruit icon when we press the shrink button. So, we need two CGAffineTransforms. Let's call one translate and the other size.

So we now have six items.

  • An array we will call bgImages
  • A way to keep track of the currentBackground
  • The state of hasMoved
  • The state of Shrunk
  • A way to transform translate (the position of our lulu fruit icon)
  • A way to transform size (the size of our lulu fruit icon)

Now that we have determined what we need and what we call them, we have one more thing to do: associate them with an internal means of doing what we want them to do. We have to associate them with a type. This is all very easy. Apple does it all for us. We just need to know what tools to reach for in our Apple tool bag and attach to each of these variables we have created.

  • For the array, Apple has an NSArray that does the job beautifully.
  • To keep track of the current background, let's just give each of the backgrounds a number of type integer (int).
  • To keep track of the buttons, we just need to know whether they have been pressed. A simple “yes” or “no” will be cool. Hmm, that's Boolean isn't it? So we'll associate Booleans with our hasMoved and hasShrunk buttons.
  • Lastly, we need to simply assign the CGAffineTransform class to our translate and size variables.

To emphasize how we will associate these named types to our six items, I want you to look at the following very carefully:

NSArray *bgImages;
int currentBackground;
bool hasMoved;
bool hasShrunk;

CGAffineTransform translate;
CGAffineTransform size;

This means that we need to type the preceding code underneath your three IBOutlets as follows:

@interface touchesViewController : UIViewController
{
    IBOutlet UIImageView *myIcon;
    IBOutlet UIImageView *myBackground;
    IBOutlet UIButton *shrinkButton;

    NSArray *bgImages;
    int currentBackground;
    bool hasMoved;
    bool hasShrunk;

    CGAffineTransform translate;
    CGAffineTransform size;
}
images

Figure 5–25. Create a few more items and then drag your first button.

25. Now and only now that we have correctly created and defined our variables do we start to connect our buttons, as actions, to the space below the @directive. Grab your Shrink button by clicking it and control-drag to the header file, right under the @directive, as illustrated in Figure 5–25.

images

Figure 5–26. Change the default type of your Shrink button to Action.

26. As shown in Figure 5–26, when you've control-dragged from the Shrink button to the header file, drop it in and make sure to change the type from outlet to action.

images

Figure 5–27. Name it shrink.

27. Once you have created the action for the shrink button, call it shrink. This is shown In Figure 5–27.

images

Figure 5–28. Control-drag and create actions for the remaining Move and Change buttons.

28. Now, on your own, control-drag first from the Move button and then from the Change button to the header file. Make sure you change them into actions and name them move and change. In Figure 5–28, you can see how it looks as we start control- dragging from the move button to the header file.

images

Figure 5–29. Make space for the getters and setters after checking that this is how your code appears.

29. Before moving on to creating the @properties for synthesis (getters and setters), I would like you to make sure that your code looks like mine in Figure 5–29.

images

Figure 5–30. After writing in your @properties, open the Navigator.

30. We now need to enter your @properties for synthesis, as explained in Chapter 4. You need to synthesize your three IBOutlets and the array with an @property with (nonatomic, retain) directives. Recall from Chapter 4 that when we make the mutability nonatomic, we're asking Apple to handle this! Also, the retain means that with respect to memory management, we will maintain control. OK, now write in the following code right above the three IBActions you entered for your buttons, as shown in Figure 5–30.

@property (retain, nonatomic) UIImageView *myIcon;
@property (retain, nonatomic) UIImageView *myBackground;
@property (retain, nonatomic) NSArray *bgImages;
@property (retain, nonatomic) UIButton *shrinkButton;

With this done, we are now finished coding your header file. Before moving onto the implementation file, I strongly encourage you to check every letter, space, semicolon, empty line, and comma of your header code against mine. When you are done, let's move towards the implementation file. OK, so this is how your header file should look:

#import <UIKit/UIKit.h>
@interface touchesViewController : UIViewController
{

 IBOutlet UIImageView *myIcon;
 IBOutlet UIImageView *myBackground;
 IBOutlet UIButton *shrinkButton;

NSArray *bgImages;
 int currentBackground;
 bool hasMoved;
 bool hasShrunk;

 CGAffineTransform translate;
 CGAffineTransform size;
 UIButton *move;
}

@property (retain, nonatomic) UIImageView *myIcon;
@property (retain, nonatomic) UIImageView *myBackground;
@property (retain, nonatomic) NSArray *bgImages;
@property (retain, nonatomic) UIButton *shrinkButton;
- (IBAction)shrink:(id)sender;
- (IBAction)move:(id)sender;
- (IBAction)change:(id)sender;

@end

Once you are confident that every line of your code matches mine, you need to start getting your view area ready to do some huge coding. Start by opening the Navigator panel, which pops up on the panel on the left-hand side of your screen, as illustrated in Figure 5–30.

images

Figure 5–31. After opening the Navigator, close the Assistant and click the Standard editor.

31. We no longer need to see either the nib or the Assistant. We just need wide open spaces to code your implementation file. Now that you've opened the Navigator, close the Assistantand open the Standard editor, as illustrated in Figure 5–31. Now go into the navigation pane and click your implementation file: touchesViewController.m.

Working in the Implementation File

In this section, I will teach you how to go about the first two tasks; one needs to be performed immediately upon opening the implementation file. The first task is synthesis, which is typically only one line that you will code. Second is the viewDidLoad method that typically instantiates by itself; however, in more complex code, we need to add code into the viewDidLoad method, as we will today.

Synthesis

I have made a point to encourage students and readers to grow into the habit of always synthesizing in the implementation immediately after coding the @property directives in the header files. You may have noticed that both in Chapter 4 and in this chapter, the last code I wrote in the header file was the @property directives for synthesis. This is because if you get into the habit of immediately performing synthesis on the items you just coded in the header file, you will not forget to do it at all—you won't have to waste time going back and refreshing your memory as to what you were going to synthesize.

We just performed @synthesis on myIcon, myBackground, bgImages and shrinkButton. This is what we need to synthesize first when we open up the header. What follows is how I think about it; this makes it very easy.

@implementation touchesViewController
@synthesize   items you just performed @properties on
- (void)didReceiveMemoryWarning
...
...
...

Now, by plugging that idea into this application, we get

@implementation touchesViewController
@synthesize  myIcon, myBackground, bgImages, shrinkButton;
- (void)didReceiveMemoryWarning
...
...
...
viewDidLoad

The code inside the viewDidLoad method runs after machine language code reserves some space in memory for your View. You will notice that the first thing called inside viewDidLoad is its superclass,superviewDidLoad. Now before you freak out, just as rats are a subclass of rodents, viewDidLoad is a subclass of superviewDidLoad, so the first thing Apple gets viewDidLoad to do is call all the code from its superclass. It's here, at this exact moment of time, that we need to perform some tasks.

- (void)viewDidLoad
{
    [super viewDidLoad];
Set all our button and backgrounds to the start state
Create an array with all our wallpapers inside of it
Set how much the shrink button will shrink the lulu fruit icon
Set how much the move button will move the lulu fruit icon
Set the background image to the current background image

}
Set Buttons and Backgrounds to the Start State

Let's look at how to set all our buttons and backgrounds to their start state. This is to create a clean slate before the program starts to run. In order to create a clean slate in code, we need to set our state-changing variables to zero (or to nil). We have three such variables that tell us whether a state has changes: hasMoved, hasShrunk, and currentBackground. Remember that both hasMoved and hasShrunk are Booleans, so they can either be “YES” or “NO.” The obvious start state for these is that they have not been moved yet. So, we need to set both hasMoved and hasShrunk to “NO.” This leaves us with currentBackground, which keeps track of which one of our five wallpapers is currently In the background and viewed by the user. Recall that we assigned currentBackground to be of type integer. This is easy: we simply set it to zero. See the following bold print:

- (void)viewDidLoad
{
    [super viewDidLoad];
hasMoved = NO;
    hasShrunk = NO;
    currentBackground = 0;

Create an array with all our wallpapers inside of it
Set how much the shrink button will shrink the lulu fruit icon
Set how much the move button will move the lulu fruit icon
Set the background image to the current background image
}
Create Our Array with All Our Wallpapers Inside of It

Now, we need to create an array, which is just a list of things, and fill it up with our wallpapers. The supernova geeky way to say this is as follows: “We need to create an NSArray object and initialize it with some objects of type png.” That's not too obtuse, is it? Recall that we did declare the array in our header file. Often, students are so fearful of arrays that they forget to declare them when they write their exam code. Recall in the header file we wrote “NSArray *bgImages,”so we have declared an array and called it bgImages. Right away, we know we need to write “bgImages = (the stuff that will make our array come to life).” There are many complex ways to use arrays, but we will use the plain cheeseburger . . .or should I say . . . Apple methods using the NSArray initializers. They are pretty much the same as the factory methods, only you do the allocation yourself, which is in the form of NSArray.

name of your array = [[NSArray alloc] initWithObjects: @"your 1st object", @" your 2nd
object ", @" your 3rd object ", nil];

This looks all cluttered, so looking at the end of it, you'll see that all your objects are separated by commas; then, we tell the array it has ended by putting that“”nil”” at the end. Let's do two things here. First, let's plug the real name of our array—bgImages—into the template, and then we'll take the contents between these commas and place them onto their own separate lines and see if this makes more sense.

bgImages array  = [[NSArray alloc] initWithObjects:
@"your 1st object",
@" your 2nd object ",
@" your 3rd object ",
nil];

Pretty cool, huh?! This really spooky code is actually making sense to you! Yeah! OK, we're not quite there yet though. We need to do one more thing before we bring this array to life. We need to wrap our heads around the UIImage class reference, which is an object the folks at Apple wrote to display images. Our objects are images, but really, they are filenames that contain images. We need to use the UIImage together with a method called imageNamed that returns image objects connected to filenames. So, for each file name, we need to use UIImageimageNamed. I have illustrated this as follows:

name of your array  = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:@ »WallPaper_01.png »],
[UIImage imageNamed:@ »WallPaper_02.png »],
[UIImage imageNamed:@ »WallPaper_03.png »],
[UIImage imageNamed:@ »WallPaper_04.png »],
[UIImage imageNamed:@ »WallPaper_05.png »],
nil];

With that code, we have created an array that contains our five images. All we need to do now is insert it into our code. See the following bold print:

- (void)viewDidLoad
{
    [super viewDidLoad];
hasMoved = NO;
    hasShrunk = NO;
    currentBackground = 0;

bgImages = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:@ »WallPaper_01.png »],
                [UIImage imageNamed:@ »WallPaper_02.png »],
                [UIImage imageNamed:@ »WallPaper_03.png »],
                [UIImage imageNamed:@ »WallPaper_04.png »],
                [UIImage imageNamed:@ »WallPaper_05.png »],
                nil];
Set how much the shrink button will shrink the lulu fruit icon
Set how much the move button will move the lulu fruit icon
Set the background image to the current background image
}
Set HowMuch We Will Shrink the Lulu Fruit Icon

It's really easy to set how much we will shrink the lulu fruit icon when we press the Shrink button. Remember when we discussed at the beginning of this chapter how CGAffine is able to obey us when we instruct it change our object's position, angle, shape, scale, and so on? Well now we are going to use it. I have randomly decided to shrink the lulu fruit icon by 25%. This means that we need to tell CGAffine two things: first that we want to scale the image, and second, how much we want to scale it on the x- and y-axes. We want to use CGAffine to scale the stuff we use . . . hmmm . . . let's guess . . . Ah! how about CGAffineTransformMakeScale? Yes! We're correct. Ok, now for the next assignment. To scale the image by 25%, we need to scale both the x- and y-axes equally at 0.25; but before we enter this into the code, remember in our header file we created a variable called size of type CGAffineTransform? Well we need to set the size variable equal to the 25% shrinkage we tell the CGAffineTransformMakeScale code to perform. This is illustrated by the following:

- (void)viewDidLoad
{
    [super viewDidLoad];
hasMoved = NO;
    hasShrunk = NO;
    currentBackground = 0;

bgImages = [[NSArray alloc] initWithObjects:
                [UIImage imageNamed:@"WallPaper_01.png"],
                [UIImage imageNamed:@ »WallPaper_02.png »],
                [UIImage imageNamed:@ »WallPaper_03.png »],
                [UIImage imageNamed:@ »WallPaper_04.png »],
                [UIImage imageNamed:@ »WallPaper_05.png »],
                nil];
size = CGAffineTransformMakeScale(.25, .25);
Set how much the move button will move the lulu fruit icon
Set the background image to the current background image
}
Set How Much We Will Move the Lulu Fruit Icon

In the same way that we made CGAffineTransformMakeScale tell our size variable to hold the amount we will shrink the icon, we will now use Translation. This is a geeky way of saying how much we will make it travel across the screen in CGAffineTransformMakeTranslation to tell the move variable we created in our header file of type CGAffineTransform to hold the amount we want to move it. I have randomly chosen to only move our lulu fruit icon up 100 pixels on the y-axis. “Up” means we need to subtract pixels from the y-axis. We only want to subtract 100 pixels on the y-axis and leave the x-axis alone (0,-100). This is illustrated as follows:

- (void)viewDidLoad
{
    [super viewDidLoad];
hasMoved = NO;
    hasShrunk = NO;
    currentBackground = 0;

bgImages = [[NSArray alloc] initWithObjects:
                [UIImage imageNamed:@ »WallPaper_01.png »],
                [UIImage imageNamed:@ »WallPaper_02.png »],
                [UIImage imageNamed:@ »WallPaper_03.png »],
                [UIImage imageNamed:@ »WallPaper_04.png »],
                [UIImage imageNamed:@ »WallPaper_05.png »],
                nil];
size = CGAffineTransformMakeScale(.25, .25);
    translate = CGAffineTransformMakeTranslation(0,-100);
Set the background image to the current background image
}
Set the Background Image to the Current Background Image

The last job we need to do in the viewDidLoad is to set the background image to the current background image. What does this mean!? I can just hear you saying this out loud and scratching your head. Let's think about this. We have created an array that holds our five images. We will set each of those images with a number. When we press the Change button, whatever number image is on our background, we will replace it with the next one. We have set currentBackground to zero. So, the first time somebody presses the Change button, it will use the code we have yet to code to change the currentBackground from 0 to 0+1, which means that the current background will now be the next background in the array.

NOTE: I am not going to explain the code at this point because most of us just paste it in when we need to get the object at an index and place inside a variable we created.

This is how I want you to use it now and later on your own: your variable that contains your image will be equal to [bgImagesobjectAtIndex:your variable that in our case holds the back ground image]. Don't think about this too much. Just use it as I have illustrated in the following code.

- (void)viewDidLoad
{
    [super viewDidLoad];
hasMoved = NO;
    hasShrunk = NO;
    currentBackground = 0;

bgImages = [[NSArray alloc] initWithObjects:
                [UIImage imageNamed:@ »WallPaper_01.png »],
                [UIImage imageNamed:@ »WallPaper_02.png »],
                [UIImage imageNamed:@ »WallPaper_03.png »],
                [UIImage imageNamed:@ »WallPaper_04.png »],
                [UIImage imageNamed:@ »WallPaper_05.png »],
                nil];
size = CGAffineTransformMakeScale(.25, .25);
    translate = CGAffineTransformMakeTranslation(0,-100);
 myBackground.image = [bgImages objectAtIndex:currentBackground];
}
images

Figure 5–32. Check that your code is complete in the implementation file.

32. With all of this completed, your viewDidLoad should look like mine, as illustrated in Figure 5–32.

New Heading

We will be personally handling much of how we unload memory associated with our views. We will handle this with our own handwritten code as we switch from one background to the next, so we can delete some of the boilerplate code Apple instantiated for us.

images

Figure 5–33. Trim down your viewDidUnload.

33. As illustrated in Figure 5–33, go to your viewDidUnload and select all the code from the beginning of [myIcon release] to the end of your shrinkButton = nil and delete it all.

images

Figure 5–34. Code your touchesMoved method.

34. Now we are going to code the touchesMoved method. Yes, I know you don't even see it yet! What I want you to do after deleting the appropriate code in your viewDidUnload is scroll down through all the methods Apple instantiated for you. Scroll through your viewWillAppear, viewDidAppear, viewWillDisappear, viewDidDisappear, and shouldAutorotateToInterfaceOrientation. Now you will see three methods for our three actions we created in the header file for our three buttons.

- (IBAction)shrink:(id)sender {
}
- (IBAction)move:(id)sender {
}
- (IBAction)change:(id)sender {
}

@end

This is really great because we will place all our code inside these methods, but hold on . . .we're missing the method that will handle our touching and moving the lulu fruit icon with our fingertips! Yup, we need to create that from scratch. Right above the shrink method, which is at the top, I want you to create about four blank lines and then simply enter touches and code completion will bring up touchesMoved; press Enter, and then enter touches again, and the code completion will bring up touches withEvent:(UIEvent *)event{. Now you will have all four methods you need to code, as illustrated by the following, where I have highlighted the four variables we created in the header file.

-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
}
- (IBAction)shrink:(id)sender {
}
- (IBAction)move:(id)sender {
}
- (IBAction)change:(id)sender {
}
@end

Now we can enter the code inside our touchesMoved class. But let's look at it from a high altitude to start off with. What do we want the touchesMoved method to do? Well, this may not seem obvious, but we simply want the touchesMoved method to do the following:

-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
Grab code that can sense all touches on the screen
Check if a touch on the screen is on the lulu fruit icon. If yes then
Check if icon was moved and shrunk using buttons if yes then
Keep shrunk size and move icon to its position before move button
Check if icon was moved and not shrunk using buttons if yes then
Move icon to its position before move button
Set icon to be at the current touch location
}

Part of my teaching method is that I do not always teach you everything. You've seen this already when we blindly coded the first couple of hello worlds. At this point I'm going to teach you how to use certain tools to perform tasks. I will not teach you how all of these tools work right now, but I am going to teach you what tool to grab. At this point, we need to get code that can sense all touches on the screen. I want you to just remember that when you want the User Interface to do cool stuff with touches, we need to first call code Apple wrote that senses and records all touches. So, type in UITouches and one of the options the code completion will present is UITouch *touch = [[event allTouches] anyObject], and this is the tool I want you to invoke before you do anything with touches. Don't think about how it works right now. Just know to call it at this point. Refer to the bold print in the following example.

-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
Check if a touch on the screen is on the lulu fruit icon.  If yes then   
Check if icon was moved and shrunk using buttons if yes then
Keep shrunk size and move icon to its position before move button
Check if icon was moved and not shrunk using buttons if yes then
Move icon to its position before move button
Set icon to be at the current touch location
}

Now we need an if statement to check if a touch on the screen is on the lulu fruit icon. We need to know that the iPhone looks at the rectangle that our object fits into, and see if the person's finger is within that rectangle. To do this, we use if (CGRectContainsPoint([myIcon frame], [touch locationInView:nil])). You will only need to type in if and CGRect, and then touch and code completion will fill in the rest. We will nest two more if statements inside of this if statement. Notice how I have taken our road map tasks and nested them inside this if statement as illustrated in the following:

-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
    if (CGRectContainsPoint([myIcon frame], [touch locationInView:nil]))
    {
Check if icon was moved and shrunk using buttons if yes then {
Keep shrunk size and move icon to its position before move button
}

Check if icon was moved and not shrunk using buttons if yes then {
Move icon to its position before move button
     }
Set icon to be at the current touch location
}
}

At this point, two nested conditions need to be inserted inside the if statement we just created. But let's think about this. All we want to do is test to see whether the lulu fruit icon has been moved by the buttons, and if it has, regardless of whether it's been shrunk, we need to reset whether it was moved back to a state in which it hadn't moved. The two conditions that would have moved the lulu fruit icon are: when we moved it and shrank it, or when we moved it and didn't shrink it; either way, we want to change the state to not being moved so that when the user's finger touches the lulu fruit icon, we can say, “You were not moved, but now you are being moved.” We cannot say, “You were moved and now you're being moved again.”

-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
    if (CGRectContainsPoint([myIcon frame], [touch locationInView:nil]))
    {
        if (hasMoved == YES && hasShrunk == YES) {
            myIcon.transform = CGAffineTransformTranslate(size, 0, 0);
            hasMoved = NO;
}

if (hasMoved == YES && hasShrunk == NO) {
            myIcon.transform = CGAffineTransformMakeTranslation(0,0);
            hasMoved = NO;
}

Set icon to be at the current touch location
}
}

NOTE: If you were watching the video, in the second if statement, I wrote myIcon.transform = translate, not CGAffineTransformMakeTranslation(0,0); It does not make too much difference, but it is better to use the latter. I did change it so in the code that you download, it will also be the latter.

The last thing we need to do is set the location of the icon to the exact position that the finger is moving it at any moment. This is stock boilerplate code that you will use over and over again to keep track of an object as one's finger moves it around the screen. We use the variable name.center = [touch locationInView:nil], as indicated in the following code:

-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
    if (CGRectContainsPoint([myIcon frame], [touch locationInView:nil]))
    {
        if (hasMoved == YES && hasShrunk == YES) {
            myIcon.transform = CGAffineTransformTranslate(size, 0, 0);
            hasMoved = NO;
}

 if (hasMoved == YES && hasShrunk == NO) {
            myIcon.transform = CGAffineTransformMakeTranslation(0,0);
            hasMoved = NO;
     }

myIcon.center = [touch locationInView:nil];
    }
}

We have now completed writing the touchesMoved method. Compare your code to how mine looks in Figure 5–34.

Coding the Shrink Button

We now want to write the code we will invoke once the user presses the shrink button.

images

Figure 5–35. Coding the shrink method

35. Remember, in the header file, we created an outlet that allowed us to change the font from “Shrink” to “Grow” once somebody pressed the button? This is because we cannot allow the lulu fruit to be shrunk twice in a row, or it would virtually disappear! So, the first thing we need to do is change the text. The second thing we need to do is keep track of the possible state of the Shrink and Move buttons, so that we can tell the CGAffine to properly transform the lulu fruit icon for us. The code looks something like this:

-(IBAction)shrink:(id)sender
{
if it has not been shrunk, keep the text saying Shrink, else change it to Grow
if it has not been shrunk or moved – do stuff
else if it has not been shrunk and has been moved – do stuff
else if it has been shrunk and moved – do stuff
else – do stuff
}

To change the text, we will use the setTitle and forState:UIControlStateNormal using the following format: your variable namesetTitle:@"your text" forState:UIControlStateNormal. We have called the outlet for our Shrink button, shrinkButton, when we declared it many years ago in the header file. The text we will use will be “Grow" once it has been changed, and then “Shrink" once it has been changed again; this loop continues forever as illustrated by the following.

-(IBAction)shrink:(id)sender
{
    if (hasShrunk) {
        [shrinkButton setTitle:@"Shrink" forState:UIControlStateNormal];
    } else {
        [shrinkButton setTitle:@"Grow" forState:UIControlStateNormal];
    }
if it has not been shrunk or moved – do stuff
else if it has not been shrunk and has been moved – do stuff
else if it has been shrunk and moved – do stuff
else – do stuff
}

We write nested if statements by starting with an if and ending with and else; between the beginning if and the ending else if, we stick in all the else ifs we need. In our case, I have randomly chosen to arrange the if statements as follows: if ‘both NO’; else ifNO and YES'; else if ‘both YES'; and finally else whatever remains, which is ‘YES and NO'. Converting the aforementioned into code is illustrated as follows:

-(IBAction)shrink:(id)sender
{
    if (hasShrunk) {
        [shrinkButton setTitle:@"Shrink" forState:UIControlStateNormal];
    } else {
        [shrinkButton setTitle:@"Grow" forState:UIControlStateNormal];
    }

if(hasShrunk == NO && hasMoved == NO)
{
– do stuff
}
else if(hasShrunk == NO && hasMoved == YES)
{
– do stuff
}
else if(hasShrunk == YES && hasMoved == YES)
{
– do stuff
}
else
{
– do stuff
}
}

Before we “do stuff” to the state of the lulu fruit icon within each nested if, we need to perform, within each nested if, certain preliminary chores. We need to tell the microprocessor how many seconds we want the ‘stuff’ to last, and then, after doing whatever stuff we want to our lulu fruit icon (using CGAffineTransform), we need to update its state. This is illustrated in the following non-code, in plain English:

-(IBAction)shrink:(id)sender
{
    if (hasShrunk) {
        [shrinkButton setTitle:@"Shrink" forState:UIControlStateNormal];
    } else {
        [shrinkButton setTitle:@"Grow" forState:UIControlStateNormal];
    }

if(hasShrunk == NO && hasMoved == NO)
{
Start animation with duration of 1 second
– do stuff
Commit animations and update shrunk state
}
else if(hasShrunk == NO && hasMoved == YES)
{
Start animation with duration of 1 second
– do stuff
Commit animations and update shrunk state
}
else if(hasShrunk == YES && hasMoved == YES)
{
Start animation with duration of 1 second
– do stuff
Commit animations and update shrunk state
}
else
{
Start animation with duration of 1 second
– do stuff
Commit animations and update shrunk state
}
}

I will keep this non-code, plain English roadmap of these trivial chores in this state for a while, so it does not clutter up the coding landscape as we focus on more important elements. We now need to take a fairly high level approach to what we will do in each of the four cases.

1. If: Both of the buttons have not been pressed and we press the Shrink button, we will

  • Shrink the lulu fruit icon.

2. Else if: The Shrink button has not been pressed, but we do press the Move button, we will

  • Keep the icon where we moved it, but go ahead and shrink the lulu fruit icon.

3. Else If: Both the Shrink and Move buttons have been pressed, and we press the Shrink button again, we will

  • Grow the lulu fruit icon back up to its original state and move it to its moved location.
  • Recall that we have already coded the text inside the Shrink button to change from Shrink to Grow.

4. Else if: The Shrink button has been pressed, but the Move button has not been pressed, we will

  • Grow the lulu fruit icon back up to its original state and keep it in its current location.

Keeping the preceding scenario in non-code, plain English, this is how it will be placed inside the code:

-(IBAction)shrink:(id)sender

{
    if (hasShrunk) {
        [shrinkButton setTitle:@"Shrink" forState:UIControlStateNormal];
    } else {
        [shrinkButton setTitle:@"Grow" forState:UIControlStateNormal];
    }

if(hasShrunk == NO && hasMoved == NO)
{
Start animation with duration of 1 second
Shrink icon
Commit animations and update shrunk state
}
else if(hasShrunk == NO && hasMoved == YES)
{
Start animation with duration of 1 second
Keep icon moved and shrink icon
Commit animations and update shrunk state
}
else if(hasShrunk == YES && hasMoved == YES)
{
Start animation with duration of 1 second
Keep icon moved and change icon back to normal size
Commit animations and update shrunk state
}
else
{
Start animation with duration of 1 second
Move icon back to normal size and location
Commit animations and update shrunk state
}
}

Now, we will change it to real code.

  • In the first case, to shrink the lulu fruit icon, do the following:
    • Set the transform of the lulu fruit icon to be the size that is contained in our variable size.
  • In the second case, to keep the icon moved where we moved it, but still shrink it, we will do the following:
    • Set the transform of the lulu fruit icon to be located at the place where the transform method has moved it.
    • But now we've lost “size,” so we need to re- shrink it to .25 of its state.
  • In the third case, to grow the lulu fruit icon back up to its original state and move it to its moved location, the following should be done:
    • Set the transform of the lulu fruit icon to be located at the place where the transform method has moved it.
    • Now, bring it back up to its original size.
  • In the last case, to grow the lulu fruit icon back up to its original state and keep it in its current location, do the following:
    • Bring it all back to its original state.

Placing the preceding examples into the code gives us the following:

-(IBAction)shrink:(id)sender
{
    if (hasShrunk) {
        [shrinkButton setTitle:@"Shrink" forState:UIControlStateNormal];
    } else {
        [shrinkButton setTitle:@"Grow" forState:UIControlStateNormal];
    }

if(hasShrunk == NO && hasMoved == NO)
{
Start animation with duration of 1 second
myIcon.transform = size;
Commit animations and update shrunk state
}
else if(hasShrunk == NO && hasMoved == YES)
{
Start animation with duration of 1 second
myIcon.transform = CGAffineTransformScale(translate,.25, .25);
Commit animations and update shrunk state
}
else if(hasShrunk == YES && hasMoved == YES)
{
Start animation with duration of 1 second
myIcon.transform = CGAffineTransformScale(translate,1, 1);
Commit animations and update shrunk state
}
else
{
Start animation with duration of 1 second
myIcon.transform = CGAffineTransformIdentity;
Commit animations and update shrunk state
}
}

We now need to think about how we will update the shrunk state of the lulu fruit icon. In the first two cases, we did shrink the lulu icon, so we need to update the shrunk state to YES. In the last two cases, it was not shrunk, so we should update the shrunk state as being NO. See the following code:

NOTE: If this does not make sense, then think about it by looking at the explanation of the preceding code. Or just go along with it for now if your brain is tired—it's OK— just follow along.

-(IBAction)shrink:(id)sender
{
    if (hasShrunk) {
        [shrinkButton setTitle:@"Shrink" forState:UIControlStateNormal];
    } else {
        [shrinkButton setTitle:@"Grow" forState:UIControlStateNormal];
    }

if(hasShrunk == NO && hasMoved == NO)
{
Start animation with duration of 1 second
myIcon.transform = size;
Commit animations
hasShrunk = YES;
}
else if(hasShrunk == NO && hasMoved == YES)
{
Start animation with duration of 1 second
myIcon.transform = CGAffineTransformScale(translate,.25, .25);
Commit animations
hasShrunk = YES;
}
else if(hasShrunk == YES && hasMoved == YES)
{
Start animation with duration of 1 second
myIcon.transform = CGAffineTransformScale(translate,1, 1);
Commit animations
hasShrunk = NO;
}
else
{
Start animation with duration of 1 second
myIcon.transform = CGAffineTransformIdentity;
Commit animations
hasShrunk = NO;
}
}

Next, we will change the plain English chores within each nested if to actual code. We clear the state of the animation and set the animation to 1 second (I randomly chose 1 second, you can choose something else). After we perform our actions on the lulu fruit, we commit the actions. This is illustrated by the following code:

-(IBAction)shrink:(id)sender
{
    if (hasShrunk) {
        [shrinkButton setTitle:@"Shrink" forState:UIControlStateNormal];
    } else {
        [shrinkButton setTitle:@"Grow" forState:UIControlStateNormal];
    }

if(hasShrunk == NO && hasMoved == NO)
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
myIcon.transform = size;
[UIView commitAnimations];
hasShrunk = YES;
}
else if(hasShrunk == NO && hasMoved == YES)
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
myIcon.transform = CGAffineTransformScale(translate,.25, .25);
[UIView commitAnimations];
hasShrunk = YES;
}
else if(hasShrunk == YES && hasMoved == YES)
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
myIcon.transform = CGAffineTransformScale(translate,1, 1);
[UIView commitAnimations];
hasShrunk = NO;
}
else
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
myIcon.transform = CGAffineTransformIdentity;
[UIView commitAnimations];
hasShrunk = NO;
}
}

Lastly, we add some spacing between the sections within each conditional statement, and it should look very similar to my code in Figure 5–35.

Coding the Move Button

Programming the code that makes the Move button operate is exactly the same as the code we used for the Shrink button, except that we do not change the text inside the button, so leave that out.

images

Figure 5–36. Coding the move method

36. We are then left with the same four states. Simply change all the cases of “shrunk” to “moved” and it's identical. Check your code against mine in Figure 5–36.

NOTE: I suggest that you first cut and paste the first “if” statements from the shrink method then swap out the shrinks and moves. After this, paste it three times; change the relevant cases of “if” to “else if” and “else.” Lastly, change the scaling to moving in the CGAffineTransformTranslates.

Coding the Change Button

The only thing left to do now is to write the code that will change the backgrounds when we press the Change button.

images

Figure 5–37. Code the change method.

37. We will essentially perform five jobs: increment the current background; make sure the incrementation keeps the images contained in our array; initialize the UIView; create animations for our backgrounds as they get loaded; and lastly, commit and change the background. Our starting roadmap for our change method is as follows:

-(IBAction)change:(id)sender
{
Increment background to the next background image
Check to see currentBackground doesn't go off the array
Initialize the UIView
Create animations
Commit and change
}

I have said before that each time we press the Change button, it will change the image by changing the number of the background image. If wallPaper_01 is presently housed in the background and we press Change, then we will increment it; meaning, we will add one and bring on wallPaper_02 as the next background. All this means is that each time the Change button is pressed, before we do anything else, we need to increment the currentBackground as follows:

-(IBAction)change:(id)sender
{
currentBackground++;
Check to see currentBackground doesn't go off the array
Initialize the UIView
Create animations
Commit and change
}

If we keep incrementing, then we will go beyond the number of images lined up in our array. Therefore, we need to reset the count back to zero once we reach the number of images in our array. This is illustrated by the following:

-(IBAction)change:(id)sender
{
currentBackground++;
if(currentBackground >= [bgImages count])
                currentBackground = 0;
Initialize the UIView
Create animations
Commit and change
}

To initialize the UIView, we need to do two things, but I've added a third task just to be cool. We have to reset (reboot, set to zero—however you want to say it), the beginAnimations method that those incredibly supercalifragilistic dudes at Apple wrote! Then, we need to set how long each animation is going to be. As I mentioned when we did the initializing before, I set the initializing in-between changes to 1 second. To be cool, I incorporated a third task: determining how smoothly each animation will start and end using the UIViewAnimationCurveEaseInOut method. This is illustrated by the following:

-(IBAction)change:(id)sender
{
currentBackground++;
if(currentBackground >= [bgImages count])
currentBackground = 0;
[UIView beginAnimations:@"changeview" context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
Create animations
Commit and change
}

NOTE: To actually change the backgrounds, we need be careful how we wrap our heads around this concept. Read this carefully and do your best to follow along.

We divide the changing of each background into two steps.

1. First, we ask whether the current background's numerical value, or tag, is the one we're dealing with. If it's true, then we perform the code within the squiggly brackets (shown in the next bullet).

2. We will then use the setAnimationTransition method to perform whatever other method we have chosen. There are methods to curl up, curl down, move in from the left or right, flip this way, do that, or do this. Or you can create your own method . . . when you become an uber geek. Right now, I'm just using curls and page flips, so I will call these transitions appropriately.

Looking at it a little more closely, for each animation, we use the form as follows:

if(currentBackground ==the # we want)
[UIView setAnimationTransition:
imagesUIViewAnimationTransition the animation we choose
images forView:self.view
images cache:YES];

Now repeating this method and using randomly chosen animations for each animation, the code takes on the following form:

-(IBAction)change:(id)sender
{
currentBackground++;
if(currentBackground >= [bgImages count])
currentBackground = 0;
[UIView beginAnimations:@"changeview" context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
if(currentBackground == 1)
[UIView setAnimationTransition:
imagesUIViewAnimationTransitionFlipFromLeft
imagesorView:self.
imagesview cache:YES];

if(currentBackground == 2)
[UIView setAnimationTransition:
images UIViewAnimationTransitionCurlDown
imagesorView:self.
imagesview cache:YES];

if(currentBackground == 3)
[UIView setAnimationTransition:
images UIViewAnimationTransitionCurlUp
imagesorView:self.
imagesview cache:YES];

if(currentBackground == 4)
[UIView setAnimationTransition:
images UIViewAnimationTransitionFlipFromRight
imagesorView:self.
imagesview cache:YES];

Commit and change

}

The last step, again as we did before we simply need to commit the change and execute the code:

-(IBAction)change:(id)sender
{
currentBackground++;
if(currentBackground >= [bgImages count])
currentBackground = 0;
[UIView beginAnimations:@"changeview" context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
if(currentBackground == 1)
[UIView setAnimationTransition:
imagesUIViewAnimationTransitionFlipFromLeft
imagesorView:self.
imagesview cache:YES];

if(currentBackground == 2)
[UIView setAnimationTransition:
images UIViewAnimationTransitionCurlDown
imagesorView:self.
imagesview cache:YES];

if(currentBackground == 3)
[UIView setAnimationTransition:
images UIViewAnimationTransitionCurlUp
imagesorView:self.
imagesview cache:YES];

if(currentBackground == 4)
[UIView setAnimationTransition:
images UIViewAnimationTransitionFlipFromRight
imagesorView:self.
imagesview cache:YES];

[UIView commitAnimations];
myBackground.image = [bgImages imagesobjectAtIndex:currentBackground];
}

Check your code against mine, as illustrated in Figure 5–37. We're done! Can you believe that? All you need to do is run it and your code will work beautifully . . . Ahh … NOT! Not unless you're a super geek!

Running the Code

Let me explain something. The odds that it will work are small and that's OK! It's OK that your code does not work at first. Expecting your code to run beautifully the first time is similar to what my mother told me a couple of years ago. She called from across town at 5:00 o'clock in the afternoon and said, “Darling I'm just leaving now; I know it's 5:00 o'clock, but I should be there soon because I hope there will not be too much traffic today!” I could not believe what she had just said. I replied, “Mom, rather than expecting to be here in 20 minutes hoping there will not be traffic only to be horribly let down, why don't you expect it to take one hour and enjoy that new Deva Premal meditation CD I bought you? Relax and enjoy yourself!”

Likewise, expect there to be errors. Debugging our code is a HUGE part of being a computer scientist and expecting not to see any is only going to let you down. If there were no errors then you'd be lucky!

images

Figure 5–38. The opening screen

38. Once you run it, you can do four things: press one of the three buttons or move the icon around on your screen. This initial view is seen in Figure 5–38.

images

Figure 5–39. Some more views

39. Figure 5–39 shows three images. The first background displays where the Shrink button is pressed and then it changes to Grow. On the third image, we see the beginning of the flipping of the background to the next background.

images

Figure 5–40. Views of the change backgrounds

40. Figure 5–40 illustrates the page curling to the fourth background and the lulu fruit icon being moved by the touches function.

Digging the Code

Typically, I spend time digging the code that we flew over. However, this chapter was a huge leap, and I could not justify leaving you to flip back to this section to understand what was going on while you typed the code. As far as going deeper into the code is concerned, there's not much left to dig into—we did a pretty thorough job on it. In the next Chapter, we will look at switch views; we will “quickly” run the code and then come back to what we really did in the “Digging the Code” section. Let's close this chapter and give your brain a break.

In the Chapter Ahead

In Chapter 6, we will move into the next level of complexity: switch view applications. We will examine how a team of characters or roles within your code will work together to direct an outcome, or a series of outcomes, that will give the user the sense of seamless flow.

You will learn about delegators and switch view controllers, classes and subclasses, and “lazy loads.” We will get into the nitty-gritty of the .xib files, examine the concept of memory deallocation, and learn about imbedded code comments. It's getting curiouser and curiouser. . .

Onward to the next chapter!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset