• Aucun résultat trouvé

UIDevice Notifications

Dans le document Chapter 1. A Simple iPhone Application (Page 168-174)

}

Notice that the notification object may also have a userInfo dictionary attached to it. This dictionary is used to pass added information. For example, when a keyboard is coming onto the screen, it posts a UIKeyboardDidShowNotification that has a userInfo dictionary. This dictionary contains the on-screen region that the newly visible keyboard occupies.

Here’s an example of an object posting a notification:

NSDictionary *extraInfo = ...;

NSNotification *note = [[NSNotification notificationWithName:@"LostDog"

object:self

userInfo:extraInfo];

[[NSNotificationCenter defaultCenter] postNotification:note];

This is important: the notification center does not retain the observers. If you have an object that registered itself with the notification center, that object should unregister itself before it is deallocated. If an object does not unregister itself from the notification center, the next time any notification it was registered for is posted, the center will try and send the object a message. But that object will have been deallocated, and your application will crash.

- (void)dealloc

{ [[NSNotificationCenter defaultCenter] removeObserver:self];

[super dealloc];

}

UIDevice Notifications

One object that regularly posts notifications is UIDevice. Here are the constants for the notifications that a UIDevice posts:

UIDeviceOrientationDidChangeNotification UIDeviceBatteryStateDidChangeNotification UIDeviceBatteryLevelDidChangeNotification UIDeviceProximityStateDidChangeNotification

Wouldn’t it be cool to get a message when the phone rotates? Or when the phone is placed next to the user’s face? These notifications do just that.

Create a new Window-based Application project and name it HeavyRotation.

In HeavyRotationAppDelegate.m, register to receive notifications when the orientation of the device changes:

- (BOOL)application:(UIApplication *)application

didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

// Get the device object

UIDevice *device = [UIDevice currentDevice];

// Tell it to start monitoring the accelerometer for orientation [device beginGeneratingDeviceOrientationNotifications];

// Get the notification center for the app

NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];

// Add yourself as an observer [nc addObserver:self

selector:@selector(orientationChanged:)

name:UIDeviceOrientationDidChangeNotification object:device];

[window makeKeyAndVisible];

}

Now, whenever the device’s orientation changes, the message

orientationChanged: will be sent to the instance of HeavyAppDelegate. In the same file, add an orientationChanged: method:

- (void)orientationChanged:(NSNotification *)note

{ // Log the constant that represents the current orientation

NSLog(@"orientationChanged: %d", [[note object] orientation]);

}

Build and run the application. (This is best run on the device because the simulator won’t let you achieve some orientations.)

Many classes post notifications including UIApplication,

NSManagedObjectContext, MPMoviePlayerController, NSFileHandle, UIWindow, UITextField, and UITextView. See the reference pages for these classes in the docs for details.

Autorotation

Many applications rotate and resize all of their views when the user rotates the phone. You could implement this using notifications, but it would be a lot of work.

Thankfully, Apple created autorotation to simplify the process.

When the device is rotated and if the view on screen is controlled by a view controller, the view controller is asked if it is okay to rotate the view. If the view controller agrees, the view is resized and rotated. The subviews are also resized and rotated.

To implement autorotation in HeavyRotation, you must

• override shouldAutorotateToInterfaceOrientation: in HeavyViewController to allow autorotation

• carefully set the autoresize mask on each subview so that it acts reasonably when the superview is resized to fill the rotated window.

In Xcode, create a UIViewController subclass with a XIB file and name it HeavyViewController.m.

In HeavyViewController.m, you could create an init method that specifies the NIB to load and override the designated initializer of the superclass to call that init method:

- (id)init

{ [super initWithNibName:@"HeavyViewController"

bundle:nil];

return self;

}

- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle ( return [self init];

}

However, it really isn’t necessary. The init method of UIViewController calls [self initWithNibName:nil bundle:nil]. And if the nibName is nil, the view controller assumes that the name of the NIB file is the same as the name of the view controller. Because you don’t need to initialize any instance variables, this class doesn’t need an initializer at all; the default behavior is perfect.

Have your view controller allow autorotation for any orientation except upside-down:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)x { return (x == UIInterfaceOrientationPortrait)

|| UIInterfaceOrientationIsLandscape(x);

}

(Other UIDevice orientation constants can be found in the documentation page for UIDevice.)

Drag any image from Finder into your project under the Resources group.

Double-click HeavyViewController.xib to open it in Interface Builder. Drop a slider, an image view, and two buttons onto the window. In the Attributes panel of the Inspector for the image view, set Image to your image file. Choose Aspect Fit mode to fit the image to the view without changing its aspect ratio and set the background color to gray as shown in Figure 9.1.

Figure 9.1. UIImageView

Now you need to set the autoresize mask for each view. The autoresize mask controls what happens to the view when its superview resizes. In the Size

inspector, a view is a rectangle within a rectangle. The inner rectangle represents the selected view, and the outer rectangle represents its superview (Figure 9.2).

Figure 9.2. Autosizing in Size inspector

Clicking to turn on a red arrow inside the inner box means “It’s okay if this view resizes in this dimension.” Turning on a red strut between the inner and outer box means “The distance between this edge of the view and the corresponding edge of the superview is never allowed to change.” Still confused? Check out the little movie inside the inspector that demonstrates these choices.

Select each view and set the autoresize mask appropriately. The image view should resize with the window. The slider should get wider but not taller. The buttons should stay with their respective corners but not resize (Figure 9.3).

Figure 9.3. Autoresizing mask for views

Finally, you need to create an instance of HeavyViewController and place its view

into your view hierarchy. Add the following lines of code to application:didFinishLa unchingWithOptions: in HeavyRotationAppDelegate.m. Make sure to include the import statement at the top of the file.

#import "HeavyViewController.h"

@implementation HeavyRotationAppDelegate - (BOOL)application:(UIApplication *)application

didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ...

HeavyViewController *hvc = [[HeavyViewController alloc] init];

[window addSubview:[hvc view]];

[window makeKeyAndVisible];

}

Build and run the application. It should autorotate when you rotate the device as shown in Figure 9.4.

Figure 9.4. Running rotated

Dans le document Chapter 1. A Simple iPhone Application (Page 168-174)

Documents relatifs