Figure 4-6. Creating the EightBall project
Choose a location to save the new project and create it. In the project navigator, select the project, select the EightBall target from the pop-up menu (if needed), select the General tab, and then turn off the two landscapeorientations in the supported interface orientation section, so only the portrait orientation is enabled.
Create the Interface
Select the Main.storyboard Interface Builder file and select the single view object. Using the attributes inspector set the background color to Black, as shown in Figure 4-7.
Figure 4-7. Setting main view background color
From the library, drag a new image view object into the interface. Using the size inspector to set the height and width to 320 pixels. Drag the image object so it snaps to the vertical and horizontal centering guides, as shownin Figure 4-8.
Figure 4-8. Centering the image view
Set the first constraint by control+clicking/right-clicking in the image view and dragging down a little. Release the mouse and choose the Height constraint. This will fix the height of the image view. From the Resolve AutoLayout Issues control, choose the Add Missing Constraints in View Controller. Xcode will add sufficient constraints to make them complete. Because the view was centered in the screen, Xcode will add constraints to keep itcentered.
Just as you did in Chapter 2, you’re going to add some resource image files to your project. In the project navigator, select the Images.xcassets assets catalog. In the Finder, locate the Learn iOS Development Projects folder youdownloaded in Chapter 1. Inside the Ch 4 folder you’ll find the EightBall (Resources) folder, which contains five image files. Select the files eight-ball.png and eight-ball@2x.png. With these files and your workspace window visible, drag the two image files into the assets catalog, as shown in Figure 4-9.
Figure 4-9. Adding eight-ball images to the asset catalog
Returning to your project, select Main.storyboard, and select the image view object. Using the attributes inspector set the image property to eight-ball, as shown in Figure 4-10.
Figure 4-10. Setting the image
Now you need to add a text view to display the magic message. From the object library, drag in a new text view (not a text field) object, placing it over the “window” in the middle of the eight ball Use the size inspector to set thewidth of the text view to 160 pixels and the height to 112. Center the text view using the centering guides, as shown in Figure 4-11.
Figure 4-11. Centering text view
Using the control+click/right-click gesture again, add the following constraints:
Drag up (or down), inside the text view, release, and choose a Height constraint.
Drag right (or left), inside the text view, release, and choose a Width constraint.
Drag from text view up (or down) to the image view. Choose the Center Y constraint.
Drag right (or left), from the text view to the image view. Choose the Center X
constraint.
The text view now has a fixed size and will always be centered over the image view.
Select the text view. Using the attributes inspector set the following properties:
Set text to SHAKE FOR ANSWER, on three lines (see Figure 4-12). Hold down the Option key when pressing the Return key to insert a literal “return” character into the text property field.
Make the text view color white.
Click the up arrow in the font property until it reads System 24.0.
Choose the centered (middle) alignment.
Uncheck the Editable behavior property.
Further down, find the background property and set it to default (no background).
Your interface design is finished, and should look like the one in Figure 4-12. Now it’s time to move on to the code.
Figure 4-12. Finished EightBall interface
Writing the Code
Your EBViewController object will need a connection to the text view object. Select your
EBViewController.h file and add the following property:
@property (weak,nonatomic) IBOutlet UITextView *answerView;
Now it’s time to write the code that displays the messages. Switch to your implementation file (EBViewController.m). Just above the @implementation line, add this code:
static NSString* gAnswers[] = {
@"\rYES",
@"\rNO",
@"\rMAYBE",
@"I\rDON'T\rKNOW",
@"TRY\rAGAIN\rSOON",
@"READ\rTHE\rMANUAL"
};
#define kNumberOfAnswers (sizeof(gAnswers)/sizeof(NSString*))
@interface EBViewController ()
- (void)fadeFortune;
- (void)newFortune;
@end
The first statement creates a static array of NSString string objects. Each object is one possible answer to appear in the eight ball. The \r characters are called an escape sequence. They consist of a backslash (left leaningslash) character followed by a code that tells the compiler to
replace the sequence with a special character. In this case, the \r is replaced with a literal “carriage return”
character—something you can’t type into your source without starting a new line.
The #define creates a constant, kNumberOfAnswers, that evaluates to the number of string objects in the gAnswers array. It does this by dividing the overall size of the array (sizeof(gAnswers)) by the size of a single element in thearray (sizeof(NSString*)). You do this so that you don’t have to keep track of how many strings are in the gAnswers array. If you want to add more answers, just add new elements to the array. The kNumberOfAnswers macro willchange to reflect however many there are.
The @interface EBViewController () statement declares the two methods used to update the message display: -fadeFortune and -newFortune. They are declared here, instead of in EBViewController.h, because these areprivate methods—not for use by objects other than EBViewController.
Create the two methods you just promised by adding the following code to your implementation (that is, between the @implementation and @end statements):
- (void)fadeFortune
{
[UIView animateWithDuration:0.75 animations:^{ self.answerView.alpha = 0.0;
}];
}
- (void)newFortune
{
self.answerView.text = gAnswers[arc4random_uniform(kNumberOfAnswers)];
[UIView animateWithDuration:2.0 animations:^{ self.answerView.alpha = 1.0;
}];
}
The -fadeFortune method uses iOS animation to change the alpha property of the answerView
text view object to 0. The alpha property of a view is how opaque the view appears. A value of 1 is completely opaque, 0.5 makes it 50% transparent, and a value of 0 makes it completely invisible.
-fadeFortune makes the text view object fade away to nothing, over a period of ¾ of a second.
The -newFortune method is where all the fun is. The first statement does three things:
1. The arc4random_uniform() function is called to pick a random number between 0 and a number less than kNumberOfAnswers. So if kNumberOfAnswers is 6, the function will return a random number between 0and 5 (inclusive).
2. The random number is used as an index into the gAnswers array to pick one of the constant NSString objects.
3. The random answer is used to set the text property of the text view object.
Once set, the text view object will display that text in your interface.
Finally, iOS animation is used again to change the alpha property slowly back to 1, going from invisible to opaque over a period of 2 seconds, causing the new message to gradually appear.
There’s one minor detail remaining: connecting the answerView outlet to the text view object in the interface. Switch to the Main.storyboard Interface Builder file. Select the view controller object, and use the connectionsinspector to connect the answerView outlet, as shown in
Figure 4-13.
Figure 4-13. Connecting the answerView outlet
Handling Shake Events
Your app now has everything it needs to work, except the event handling that will make it happen. In the Xcode documentation (Help ➤ Documentation and API Reference), take a look at the documentation forUIResponder. In it, you’ll find documentation for three methods:
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event
Each message is sent during a different phase of a motion event. Motion events are very simple—remember these are “high-level” events. Motion events begin and they end. If the motion is interrupted, or never finishes, your object receives a motion canceled message.
To handle motion events in your view controller, add these three event handler methods to your
EBViewController implementation:
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (motion==UIEventSubtypeMotionShake) [self fadeFortune];
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (motion==UIEventSubtypeMotionShake) [self newFortune];
}
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (motion==UIEventSubtypeMotionShake) [self newFortune];
}
Each method begins by examining the motion parameter to see if the motion event received describes the one you’re interested in (the shake motion). If not, you ignore the event. This is important. Future versions of iOS may addnew motion events; your object should only pay attention to the ones it’s designed to work with.
The -motionBegan:withEvent: handler sends a -fadeFortune message. When the user starts to shake the device, the current message fades away.
The -motionEnded:withEvent: handler sends the -newFortune message. When the shaking stops, a new fortune appears.
Finally, the -motionCancelled:withEvent: handler makes sure a message is visible if the motion was interrupted or interpreted to be some other gesture.








No comments:
Post a Comment