1. Trang chủ
  2. » Công Nghệ Thông Tin

iOS 5 Programming Cookbook phần 4 pptx

89 821 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 89
Dung lượng 3,86 MB

Nội dung

happens when the user decides to flip to the next page. The second method is called when the page view controller wants to figure out which view controller to display after the view controller which is being flipped. Xcode, as you've already seen it, has greatly simplified setting up a page-based appli- cation. All you really need to do now is to provide content to the data model (Model Controller) and on you go. If you need to customize the colors and images in your view controllers, simply do so by either using the Interface Builder to modify the .xib files directly or write your own code in the implementation of each of the view controllers. See Also XXX 2.22 Displaying Popovers with UIPopoverController Problem You want to display content on an iPad without blocking the whole screen. Solution Use popovers. Discussion Popovers are used to display additional information on the iPad screen. An example is the Safari app on the iPad. When the user taps on the Bookmarks button, she will see a popover displaying the bookmarks content on the screen (see Figure 2-71). 2.22 Displaying Popovers with UIPopoverController | 251 Figure 2-71. The bookmarks popover in the Safari app on an iPad The default behaviour of popovers is that when the user taps somewhere outside the region of the popover, the popover will automatically get dismissed. We can ask the popover to not get dismissed if the user taps on specific parts of the screen, as we will see later. Popovers present their content by using a view controller. Note that you can also navigation controllers inside popovers as navigation controllers subclass UIView Controller. Popovers can only be used on iPad devices. If you have a view controller whose code runs both on an iPad and on an iPhone, you need to make sure that you are not instantiating the popover on a device other than the iPad. Popovers can be presented to the user in two ways: 1. From inside a navigation button, an instance of UIBarButtonItem. 2. From inside a rectangular area in a view. When a device orientation is changed (the device is rotated), popovers are either dis- missed or hid temporarily. You need to make sure that you give your users a good experience by redisplaying the popover after the orientation change has settled, if pos- sible. In certain cases, your popover might get dismissed automatically after an orien- tation change. For instance, if the user taps on a navigation button in landscape mode you might display a popover on the screen. Your app is designed in a way that when the orientation changes to portrait, you will remove that navigation button from the 252 | Chapter 2: Implementing Controllers and Views navigation bar, for whatever reason. Now, the correct user experience would be to hide the popover associated with that navigation bar after the orientation of the device is changed to portrait. In some instances though, you will need to play with popovers a bit to give your users a good experience because not in all instances handling a device orientation is as straightforward as the aforementioned scenario. To create the demo popover app, we need to first come up with a strategy based on our requirements: we want to build an app with a view controller loaded inside a navigation controller. The root view controller will display a + button on the right corner of its navigation bar. When the + button is tapped on an iPad device, it will display a popover with two buttons on it. The first button will say "Photo" and the second button will say "Audio". When the same navigation button is tapped on an iPhone device, we will display an alert view with three buttons. The two aforementioned buttons and a cancel button so that the user can cancel the alert view if she wishes to. When these buttons are tapped (whether on the alert view on an iPhone or the popover on an iPad, we won't really do anything. We will simply dismiss the alert view or the popover. Let's go ahead and create a Single View universal project in Xcode and name the project Displaying_Popovers_with_UIPopoverControllerViewController and then let's go to our app delegate's header file and define a navigation controller first: #import <UIKit/UIKit.h> @class Displaying_Popovers_with_UIPopoverControllerViewController; @interface Displaying_Popovers_with_UIPopoverControllerAppDelegate : UIResponder <UIApplicationDelegate> @property (nonatomic, strong) UIWindow *window; @property (nonatomic, strong) Displaying_Popovers_with_UIPopoverControllerViewController *viewController; @property (nonatomic, strong) UINavigationController *navigationController; @end Next, we will synthesize and instantiate our navigation controller in the app delegate's implementation file and instead of the view controller, we will display the navigation controller to the user: #import "Displaying_Popovers_with_UIPopoverControllerAppDelegate.h" #import "Displaying_Popovers_with_UIPopoverControllerViewController.h" @implementation Displaying_Popovers_with_UIPopoverControllerAppDelegate @synthesize window = _window; @synthesize viewController = _viewController; @synthesize navigationController; - (BOOL) application:(UIApplication *)application 2.22 Displaying Popovers with UIPopoverController | 253 didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]]; UIUserInterfaceIdiom uiIdiom = [[UIDevice currentDevice] userInterfaceIdiom]; NSString *viewControllerClass = @"Displaying_Popovers_with_UIPopoverControllerViewController_iPad"; if (uiIdiom == UIUserInterfaceIdiomPhone) { viewControllerClass = @"Displaying_Popovers_with_UIPopoverControllerViewController_iPhone"; } self.viewController = [[Displaying_Popovers_with_UIPopoverControllerViewController alloc] initWithNibName:viewControllerClass bundle:nil]; self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController]; self.window.rootViewController = self.navigationController; [self.window makeKeyAndVisible]; return YES; } After this, we need to go into the definition file of our view controller and define a property of type UIPopoverController: #import <UIKit/UIKit.h> @interface Displaying_Popovers_with_UIPopoverControllerViewController : UIViewController <UIAlertViewDelegate> @property (nonatomic, strong) UIPopoverController *popoverController; @property (nonatomic, strong) UIBarButtonItem *barButtonAdd; @end You can see that we are also defining a property called barButtonAdd in our view con- troller. This is the navigation button which we will add on our navigation bar and our plan is to display our popover when the user taps on this button (you can read more about navigation buttons in Recipe 2.11). However, we need to make sure we instan- tiate the popover only if the device is an iPad. Before we go ahead and implement our root view controller with the navigation button, let's go ahead and create a subclass of UIViewController and name it PopoverContentViewController. We will display the con- tents of this view controller inside our popover later. See Recipe 2.7 for information about view controllers and ways of creating them. The content view controller displayed inside the popover will have two buttons (as per our requirements). However, this view controller will need to have reference to the 254 | Chapter 2: Implementing Controllers and Views popover controller in order to dismiss the popover when the user taps on any of the buttons. For this, we need to define a property in our content view controller to refer to the popover: #import <UIKit/UIKit.h> @interface PopoverContentViewController : UIViewController @property (nonatomic, strong) UIButton *buttonPhoto; @property (nonatomic, strong) UIButton *buttonAudio; /* We shouldn't define this as strong. That will create a retain cycle between the popover controller and the content view controller since the popover controller retains the content view controller and the view controller will retain the popover controller */ @property (nonatomic, weak) UIPopoverController *popoverController; @end Now we will go and synthesize these properties in the implementation file of our con- tent view controller: #import "PopoverContentViewController.h" @implementation PopoverContentViewController @synthesize buttonPhoto; @synthesize buttonAudio; @synthesize popoverController; After this, we shall go ahead and create our two buttons in the content view controller and link them to their action methods. These methods shall take care of dismissing the popover that is displaying this view controller. Remember, the popover controller will be responsible for assigning itself to the popoverController property of the content view controller: #import "PopoverContentViewController.h" @implementation PopoverContentViewController @synthesize buttonPhoto; @synthesize buttonAudio; @synthesize popoverController; - (BOOL) isInPopover{ Class popoverClass = NSClassFromString(@"UIPopoverController"); if (popoverClass != nil && UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && self.popoverController != nil){ return YES; } else { return NO; 2.22 Displaying Popovers with UIPopoverController | 255 } } - (void) gotoAppleWebsite:(id)paramSender{ if ([self isInPopover]){ /* Go to website and then dismiss popover */ [self.popoverController dismissPopoverAnimated:YES]; } else { /* Handle case for iPhone */ } } - (void) gotoAppleStoreWebsite:(id)paramSender{ if ([self isInPopover]){ /* Go to website and then dismiss popover */ [self.popoverController dismissPopoverAnimated:YES]; } else { /* Handle case for iPhone */ } } - (void)viewDidLoad{ [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; self.contentSizeForViewInPopover = CGSizeMake(200.0f, 125.0f); CGRect buttonRect = CGRectMake(20.0f, 20.0f, 160.0f, 37.0f); self.buttonPhoto = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [self.buttonPhoto setTitle:@"Photo" forState:UIControlStateNormal]; [self.buttonPhoto addTarget:self action:@selector(gotoAppleWebsite:) forControlEvents:UIControlEventTouchUpInside]; self.buttonPhoto.frame = buttonRect; [self.view addSubview:self.buttonPhoto]; buttonRect.origin.y += 50.0f; self.buttonAudio = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [self.buttonAudio setTitle:@"Audio" 256 | Chapter 2: Implementing Controllers and Views forState:UIControlStateNormal]; [self.buttonAudio addTarget:self action:@selector(gotoAppleStoreWebsite:) forControlEvents:UIControlEventTouchUpInside]; self.buttonAudio.frame = buttonRect; [self.view addSubview:self.buttonAudio]; } - (void)viewDidUnload{ [super viewDidUnload]; self.buttonPhoto = nil; self.buttonAudio = nil; } - (BOOL)shouldAutorotateToInterfaceOrientation :(UIInterfaceOrientation)interfaceOrientation{ return YES; } @end All good? Now let's go back to our root view controller and synthesize our properties: #import "Displaying_Popovers_with_UIPopoverControllerViewController.h" #import "PopoverContentViewController.h" @implementation Displaying_Popovers_with_UIPopoverControllerViewController @synthesize popoverController; @synthesize barButtonAdd; Now in the viewDidLoad method of our root view controller, we will create our navi- gation button and based on the device type, when the navigation bar is tapped, we will either display a popover (on the iPad) or an alert view (on the iPhone): - (void)viewDidLoad{ [super viewDidLoad]; /* See if this class exists on the iOS running the app */ Class popoverClass = NSClassFromString(@"UIPopoverController"); if (popoverClass != nil && UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){ PopoverContentViewController *content = [[PopoverContentViewController alloc] initWithNibName:nil bundle:nil]; self.popoverController = [[UIPopoverController alloc] initWithContentViewController:content]; 2.22 Displaying Popovers with UIPopoverController | 257 content.popoverController = self.popoverController; self.barButtonAdd = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(performAddWithPopover:)]; } else { self.barButtonAdd = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(performAddWithAlertView:)]; } [self.navigationItem setRightBarButtonItem:self.barButtonAdd animated:NO]; } - (void)viewDidUnload{ [super viewDidUnload]; self.barButtonAdd = nil; } - (BOOL)shouldAutorotateToInterfaceOrientation :(UIInterfaceOrientation)interfaceOrientation{ return YES; } The popover controller sets a reference to itself in the content view con- troller after its initialization. This is very important. A popover control- ler cannot be initialized without a content view controller. Once the popover is initialized with a content view controller, you can go ahead and change the content view controller in the popover controller, but not during the initialization. We have elected the performAddWithPopover: method to be invoked when the + navi- gation bar button is tapped on an iPad device. If the device isn't an iPad, we've asked the + navigation bar button to invoke the performAddWithAlertView: method so let's go ahead and implement these methods and also take care of the delegate methods of our alert view, so that we know what alert view button the user tapped on, on an iPhone: - (NSString *) photoButtonTitle{ return @"Photo"; } - (NSString *) audioButtonTitle{ return @"Audio"; 258 | Chapter 2: Implementing Controllers and Views } - (void) alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex{ NSString *buttonTitle = [alertView buttonTitleAtIndex:buttonIndex]; if ([buttonTitle isEqualToString:[self photoButtonTitle]]){ /* Adding a photo */ } else if ([buttonTitle isEqualToString:[self audioButtonTitle]]){ /* Adding an audio */ } } - (void) performAddWithAlertView:(id)paramSender{ [[[UIAlertView alloc] initWithTitle:nil message:@"Add " delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles: [self photoButtonTitle], [self audioButtonTitle], nil] show]; } - (void) performAddWithPopover:(id)paramSender{ [self.popoverController presentPopoverFromBarButtonItem:self.barButtonAdd permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; } If you now go ahead and run your app on iPad Simulator and tap on the + button on the navigation bar, you will see an interface similar to that shown in Figure 2-72: 2.22 Displaying Popovers with UIPopoverController | 259 Figure 2-72. Our simple popover displayed when a navigation button was tapped If you run the same universal app on the iPhone Simulator and tap the + button on the navigation bar, you will see results similar to that shown in Figure 2-73: 260 | Chapter 2: Implementing Controllers and Views [...]... edge-case in this recipe 2 64 | Chapter 2: Implementing Controllers and Views Let's have a look at the keyboard in iPhone first The keyboard can get displayed in portrait and landscape mode In portrait, the keyboard on an iPhone looks like this: Figure 2- 74 Portrait mode keyboard on an iPhone The keyboard in landscape mode on an iPhone will look similar to that shown in Figure 2- 75: 2. 24 Listening and Reacting... keyboard, please refer to the Discussion section of this recipe Discussion iOS devices do not have a physical keyboard They have a software keyboard which pops up whenever the user has to enter some text into a text entry such as a text field (UITextField, see Recipe 2. 14 for more information) or a text view (UITextView, see Recipe 2. 15 for more information) On the iPad, the user can even split the keyboard... defines a property called progress (of type float) This property tells iOS how the bar inside the progress view should be rendered This value must be in the range +0 to +1.0 If the value of +0 is given, the progress will appear to have not yet started Value of +1.0 shows the progress of 100% The progress depicted in figure to come is 0 .5 (or 50 %) To get used to creating progress views, let's immediately go... certainly not at 0, the width is the width of the whole screen, which obviously is not 162.0 in landscape and the height is 2. 24 Listening and Reacting to Keyboard Notifications | 277 almost half of the screen, which makes the value 48 0 incorrect The reason for the incorrect values is that iOS does not take into account the orientation of the device when reporting these values to your apps The frames reported... an example of the split keyboard on the iPad, in landscape mode (the keyboard can be split in landscape mode as well as the portrait mode): 2. 24 Listening and Reacting to Keyboard Notifications | 267 Figure 2-78 Split keyboard on the iPad in landscape mode iOS broadcasts various notifications related to the keyboard on the screen Here is a list of these notifications and a brief explanation for each... something similar to that shown in Figure 2-79: 2. 24 Listening and Reacting to Keyboard Notifications | 271 Figure 2-79 A table view with text fields for accessory view of each cell Go ahead now and tap on the first text field (in the first cell) Now scroll the table view all the way down to the last cell and see what happens! You cannot see the last 5- 6 cells, can you? What you can see in portrait mode... scrollToRowAtIndexPath:indexPathOfOwnerCell atScrollPosition:UITableViewScrollPositionMiddle animated:YES]; } } So here is what we are doing in this method, in that order: 2. 24 Listening and Reacting to Keyboard Notifications | 2 75 1 Retrieve the different animation properties of the keyboard, including its animation time, curve and the frame that the keyboard will have once its animation finished We... handleKeyboardWillShow: method of our view controller on an iPhone in portrait mode, we will get the following values: {{0, 2 64} , {320, 216}} If you now rotate the orientation to landscape and log the values again, you will see the following value printed out to the console window: {{0, 0}, {162, 48 0}} It is immediately obvious that the values are incorrect As you can see, the Y position of the keyboard is reported... Figure 2- 74 Portrait mode keyboard on an iPhone The keyboard in landscape mode on an iPhone will look similar to that shown in Figure 2- 75: 2. 24 Listening and Reacting to Keyboard Notifications | 2 65 Figure 2- 75 The keyboard in landscape mode on an iPhone On the iPad however, the keyboard is a bit different The most obvious difference is that the keyboard is actually much bigger in size compared to the... = 40 .0f; } return result; } It is worth noting that the location of a cell in a table view is represented by its index path An index path is the combination of the section and the row index, where the section index is the zero-based index specifying which grouping or section each cell belongs to, and the cell index is the zero-based index of that particular cell in its section See Also Recipe 3 .4 3.2 . 2- 74. Portrait mode keyboard on an iPhone The keyboard in landscape mode on an iPhone will look similar to that shown in Figure 2- 75: 2. 24 Listening and Reacting to Keyboard Notifications | 2 65 Figure. nil){ return YES; } else { return NO; 2.22 Displaying Popovers with UIPopoverController | 255 } } - (void) gotoAppleWebsite:(id)paramSender{ if ([self isInPopover]){ /* Go to website. addSubview:self.buttonPhoto]; buttonRect.origin.y += 50 .0f; self.buttonAudio = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [self.buttonAudio setTitle:@"Audio" 256 | Chapter 2: Implementing Controllers

Ngày đăng: 13/08/2014, 18:20

TỪ KHÓA LIÊN QUAN