Tải bản đầy đủ (.pdf) (10 trang)

Phát triển ứng dụng cho iPhone và iPad - part 14 doc

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (2.91 MB, 10 trang )

Changes to the RootViewController
Now you need to move on to the RootViewController . Here, you will add an NSMutableArray* to
hold the collection of surveys. You cannot simply use an
NSArray because you will need to be able
to add surveys to the collection on - the - fl y. Remember,
NSArray is immutable, meaning that once
you have created it, you cannot modify it.
In the
RootViewController header fi le, add an instance variable called surveyDataArray of type

NSMutableArray *:
NSMutableArray* surveyDataArray;
Add a property for your new surveyDataArray :
@property (nonatomic, retain) NSMutableArray* surveyDataArray;
Switch over to the RootViewController implementation fi le and modify the @synthesize
statement to synthesize your new
surveyDataArray property:
@synthesize detailViewController ,surveyDataArray ;
Modify the viewDidUnload and dealloc methods to clean up your new property:
- (void)viewDidUnload {
// Relinquish ownership of anything that can be recreated in viewDidLoad or
// on demand.
// For example: self.myOutlet = nil;
self.surveyDataArray = nil;
}


- (void)dealloc {
[detailViewController release];
[surveyDataArray release];
[super dealloc];


}
RootViewController.m
Finally, modify the viewDidLoad method to create and initialize the NSMutableArray :
- (void)viewDidLoad {
[super viewDidLoad];
self.clearsSelectionOnViewWillAppear = NO;
self.contentSizeForViewInPopover = CGSizeMake(320.0, 600.0);

NSMutableArray* array = [[NSMutableArray alloc] init];
self.surveyDataArray = array;
[array release];
}
RootViewController.m
Displaying Master/Detail Data with the UISplitViewController

99
CH004.indd 99CH004.indd 99 9/18/10 9:30:30 AM9/18/10 9:30:30 AM
100

CHAPTER 4 IPAD INTERFACE ELEMENTS
Modify the TableView Methods
The next step is to modify the Table View datasource methods to use the surveyData array as the

UITableView ’ s datasource. First, you will need to update the tableView:numberOfRowsInSection:
method to return the number of items in the array, like this:
- (NSInteger)tableView:(UITableView *)aTableView
numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [self.surveyDataArray count];
}

RootViewController.m
Now, you should change the tableView:cellForRowAtIndexPath: method to get data from the

surveyDataArray to use as the text in the table cells:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @”CellIdentifier”;

// Dequeue or create a cell of the appropriate type.
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
}

// Configure the cell.
NSDictionary* sd = [self.surveyDataArray objectAtIndex:indexPath.row];

cell.textLabel.text = [NSString stringWithFormat:@”%@, %@”,
[sd objectForKey:@”lastName”],
[sd objectForKey:@”firstName”]];
return cell;
}
RootViewController.m
In this method, you get an NSDictionary object from the surveyDataArray with an index based
on the row that the table has requested. Then, you get the

lastName and firstName strings from
the dictionary and display them in the cell ’ s
textLabel .
The last thing that you need to do in the Table View methods is to update the
tableView:
didSelectRowAtIndexPath:
method. In this method, you need to set the detailItem in the

detailViewController to the NSDictionary that you retrieve from the surveyDataArray .
This passes the data that you want to display, the survey that the user has chosen, to the

DetailViewController . Remember that the setter for the detailItem property contains code;
CH004.indd 100CH004.indd 100 9/18/10 9:30:30 AM9/18/10 9:30:30 AM
it is not just a synthesized property. This code calls the configureView method that updates
the view to display the record that the user has chosen. Here is the code for the
tableView:
didSelectRowAtIndexPath:
method:
- (void)tableView:(UITableView *)aTableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

/*
When a row is selected, set the detail View Controller’s detail item to the
item associated with the selected row.
*/
[aTableView deselectRowAtIndexPath:indexPath animated:NO];
NSDictionary* sd = [self.surveyDataArray objectAtIndex:indexPath.row];
detailViewController.detailItem = sd;
}
RootViewController.m

Adding Surveys
To complete this example, you will add code to the project to enable the user to add surveys to the
application. In the
RootViewController header, you will need to declare a method to add a survey.
You should call this method
addSurveyToDataArray and the signature should look like this:
-(void) addSurveyToDataArray: (NSDictionary*) sd;
Recall that you are using an NSDictionary to hold the data for each survey. Therefore, the

addSurveyToDataArray method accepts an NSDictionary* that holds the survey data that you
want to add to the array of completed surveys.
Next, switch over to the
RootViewController implementation. You should implement the

addSurveyToDataArray function as follows:
-(void) addSurveyToDataArray: (NSDictionary*) sd
{
NSLog (@”addSurveyToDataArray”);

// Add the survey to the results array
[self.surveyDataArray addObject:sd];

// Refresh the tableview
[self.tableView reloadData];
}
RootViewController.m
This method simply adds the dictionary object that it receives to the surveyDataArray . Then,
because the user has modifi ed the data for the Table View, you need to tell the Table View to reload
its data in order to refresh the display and show the new survey.
Displaying Master/Detail Data with the UISplitViewController


101
CH004.indd 101CH004.indd 101 9/18/10 9:30:31 AM9/18/10 9:30:31 AM
102

CHAPTER 4 IPAD INTERFACE ELEMENTS
Now, you need to move over to the DetailViewController to implement the addSurvey method.
This method runs when the user taps the Add button in the user interface. First, however,
you will need to add
#import statements to the DetailViewController header to import the

RootViewController and SurveyAppDelegate headers:
#import “RootViewController.h”
#import “SurveyAppDelegate.h”
DetailViewController.h
Now you can move into the DetailViewController implementation to implement the addSurvey
method:
-(IBAction)addSurvey:(id)sender
{
NSLog (@”addSurvey”);

// Create a new NSDictionary object to add to the results array of the root
// View Controller

// Set the values for the fields in the new object from the text fields of
// the form

NSArray *keys = [NSArray arrayWithObjects:@”firstName”, @”lastName”,
@”address”, @”phone”, @”age”, nil];
NSArray *objects = [NSArray arrayWithObjects:self.firstNameTextField.text,

self.lastNameTextField.text,
self.addressTextField.text,
self.phoneTextField.text,
[NSNumber
numberWithInteger:[ self.ageTextField.text intValue]],
nil];

NSDictionary* sData = [[NSDictionary alloc]
initWithObjects:objects forKeys:keys];


// Get a reference to the app delegate so we can get a reference to the
// Root View Controller
SurveyAppDelegate* appDelegate =
[[UIApplication sharedApplication] delegate];
RootViewController* rvc = appDelegate.rootViewController;

// Call the addSurveyToDataArray method on the rootViewController to
// add the survey data to the list
[rvc addSurveyToDataArray:sData];

// Clean up
[sData release];

}
DetailViewController.m
CH004.indd 102CH004.indd 102 9/18/10 9:30:31 AM9/18/10 9:30:31 AM
In this method, you need to build an NSDictionary that you will pass to the RootViewController
to add to the
surveyDataArray . To create the dictionary, you fi rst create two NSArray s, one for

the keys of the dictionary and one for the related objects. The keys can be any arbitrary
NSString s.
You obtain the objects for the dictionary from the
UITextField objects that you added in Interface
Builder. Once you have built your arrays, you create an
NSDictionary by passing in the objects
array and the
keys array.
Next, you need to call the
addSurveyToDataArray method on the RootViewController . If you
remember, the
RootViewController holds a reference to the DetailViewController . However,
the
DetailViewController does not hold a reference to the RootViewController . There are a
couple of ways that you can remedy this. For this example, I have chosen to simply get a reference to
the
RootViewController from the SurveyAppDelegate .
You can get a reference to the app delegate at any time by calling the
delegate method on the
application ’ s
UIApplication object. UIApplication is the core object at the root of all iPhone and
iPad applications.
UIApplication is a singleton class to which you can obtain a reference by calling
the
sharedApplication method. Once you obtain a reference to the application, you can call its

delegate method to get a reference to your application delegate. In this case, the delegate holds
references to both the
RootViewController and the DetailViewController . The code then goes
on to get a reference to the

RootViewController from the application delegate. Finally, you call
the
addSurveyToDataArray method on the RootViewController to add the newly created survey
dictionary to the array.
You are now ready to build and run the application. You should be able to add new surveys and
see them appear in the left hand pane in portrait mode. Select an item in the list and you will see
the display in the right - hand pane change to the item you selected. Rotate the device to see how the

UISplitViewController behaves in both landscape and portrait modes.
DISPLAYING DATA IN A POPOVER
Another user interface element that is new and unique to the iPad is the UIPopoverController .
You can use this controller to display information on top of the current view. This allows you
to provide context - sensitive information on top of the main application data without swapping
views as would be required in an iPhone application. The
UISplitViewController uses a

UIPopoverController to display the master data list when the device is in portrait orientation and
the user taps the button to disclose the master list. For example, when your Survey application is in
portrait orientation and the user taps the Root List button, the
RootViewController is displayed
in a
UIPopoverController .
Another interesting feature of the popover is that the user can dismiss it by simply tapping outside
its bounds. Therefore, you can use this controller to display information that might not necessarily
require any user action. In other words, the user does not have to implicitly accept or cancel any
action to dismiss the popover.
The
UIPopoverController displays a UIViewController as its content. You can build the content
view in any way that you wish. You should, however, consider the size of the popover as you are
building the view that it will contain. You should also consider the position in which you want to

Displaying Data in a Popover

103
CH004.indd 103CH004.indd 103 9/18/10 9:30:32 AM9/18/10 9:30:32 AM
104

CHAPTER 4 IPAD INTERFACE ELEMENTS
show the popover. You should display a popover next to the user interface element that displayed
it. When presenting a popover, you can either attach it to a toolbar button or provide a
CGRect
structure to give the popover a reference location. Finally, you can specify the acceptable directions
for the arrow that points from the popover to the reference location. You should generally permit
UIKit to control the location of the popover by specifying
UIPopoverArrowDirectionAny as the
permitted direction for the arrow.
In this section, you will create a
UIPopoverController and display it in the Survey application. The
popover will simply display a new
UIViewController that will show some helpful information on
performing surveys, as you can see in Figure 4 - 6.
FIGURE 4 - 6: The Survey Application Informational Popover
Building the InfoViewController
The UIPopoverController is a container that you can use to display another View Controller
anywhere on the screen on top of another view. Therefore, the fi rst thing that you need to do when
you want to display content in the popover is build the View Controller that you would like to
CH004.indd 104CH004.indd 104 9/18/10 9:30:33 AM9/18/10 9:30:33 AM
display. For the Survey application, you will create a new class called InfoViewController . Then,
you will display this class in a
UIPopoverController when the user taps an informational button.
The fi rst step is to create your new class. Add a new

UIViewController subclass called

InfoViewController to your project. As you add the class, make sure that the “ Targeted for iPad ”
and “ With XIB for user interface ” checkboxes in the New File dialog box are selected.
Open your new
InfoViewController header fi le. Add a UILabel* instance variable called

infoLabel . Then, add an IBOutlet property that you can use to set and get your new instance
variable. Finally, add a method signature for a new method called
setText . You will use the

setText method to set the text that you want to display in the popover. The header fi le for the

InfoViewController should look like this:
#import < UIKit/UIKit.h >


@interface InfoViewController : UIViewController {
UILabel* infoLabel;
}

@property (nonatomic, retain) IBOutlet UILabel* infoLabel;
-(void) setText: (NSString*) text;

@end
InfoViewController.h
Next, you will open the InfoViewController XIB fi le with Interface Builder to build the
user interface for the new View Controller. Double - click on the
InfoViewController XIB fi le
to open it in Interface Builder. For this application, the user interface will be extremely simple,

just a lone
UILabel . However, you can build views that are as complex as you want with
Interface Builder and use the methodology outlined here to display those interfaces
using popovers.
Once you have the XIB fi le opened in Interface Builder, open the Attributes inspector for the View
by pressing Command+1 or selecting Tools ➪ Attributes Inspector from the menu bar. Make
sure that you have the View selected. In the Attributes Inspector, set the Status Bar attribute to
Unspecifi ed because you do not want the view to have a status bar. Then, using the Size Inspector,
which you can open by pressing Command+3 or selecting Tools ➪ Size Inspector from the menu
bar, resize the view to a width of 320 pixels and a height of 175 pixels.
Now that you have the view confi gured correctly, add a
UILabel control and resize it to fi ll most of
the view. The exact size and position are not particularly important for this example.
Finally, connect the new
UILabel to the infoLabel property of File ’ s Owner. This connects
your code to the interface that you built in Interface Builder. You can now save your

InfoViewController XIB fi le and close Interface Builder.
Displaying Data in a Popover

105
CH004.indd 105CH004.indd 105 9/18/10 9:30:34 AM9/18/10 9:30:34 AM
106

CHAPTER 4 IPAD INTERFACE ELEMENTS
Now, you will need to add some logic to the InfoViewController implementation fi le. First, you
should add code to the
viewDidUnload and dealloc methods to clean up the instance variable and
property of the class:
- (void)viewDidUnload {

[super viewDidUnload];

self.infoLabel = nil;

// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}


- (void)dealloc {
[infoLabel release];

[super dealloc];
}
InfoViewController.m
Next, add a line to synthesize the infoLabel property:
@synthesize infoLabel;
The next step is to implement the viewDidLoad method. In this method, you will set the size of the
View Controller to display in the popover. Here is the code:
- (void)viewDidLoad {
[super viewDidLoad];

CGSize size;
size.width=320;
size.height = 175;
self.contentSizeForViewInPopover = size;
}
InfoViewController.m
The original size of the popover comes from the View Controller ’ s contentSizeForViewInPopover
property. The default size for a

UIPopoverController is 320 pixels by 1100 pixels. There
are two ways that you can change the size of the popover. First, you can set the size in the
View Controller that the popover will hold by setting the View Controller ’ s size using
the
contentSizeForViewInPopover property. Alternatively, you can set the size of the

popoverContentSize property of the Popover Controller. Keep in mind that if you use this
method and change the View Controller that you are displaying in the popover, the popover will
automatically resize to the size of the new View Controller. The custom size that you set in the

popoverContentSize property is lost.
CH004.indd 106CH004.indd 106 9/18/10 9:30:34 AM9/18/10 9:30:34 AM
In this example, you created a CGSize struct to defi ne the size of the popover in the View
Controller. You set the size to 320 pixels wide by 175 pixels high. Then, you set the

contentSizeForViewInPopover property on the View Controller.
Finally, you need to implement the
setText method that clients who want to display the

InfoViewController will use to set the text to display. This method does nothing more than set
the text in the
UILabel :
-(void) setText: (NSString*) text
{
self.infoLabel.text = text;
}
InfoViewController.m
Displaying the UIPopoverController
Now that you have a View Controller, you need to display it in a popover. You will display the
popover when the user taps a button in the

DetailViewController . Therefore, you will need to
make some changes to the
DetailViewController header fi le. First, add a #import statement for
the new
InfoViewController.h header fi le:
#import “InfoViewController.h”
Next, you will add a new action method called showInfo . The user will invoke this method when he
taps on the information button in the user interface. Here is the declaration:
-(IBAction)showInfo:(id)sender;
The next step is to add a new outlet and instance variable for the UIButton* called infoButton .
Inside of the interface declaration, add the instance variable for the
UIButton* :
UIButton* infoButton;
Outside of the interface declaration, declare the infoButton property:
@property (nonatomic, retain) IBOutlet UIButton* infoButton;
Now add an instance variable for the UIPopoverController . Call it infoPopover :
UIPopoverController *infoPopover;
Add a property for the infoPopover :
@property (nonatomic, retain) UIPopoverController *infoPopover;
Now you need to move over to the DetailViewController implementation fi le.
Displaying Data in a Popover

107
CH004.indd 107CH004.indd 107 9/18/10 9:30:35 AM9/18/10 9:30:35 AM
108

CHAPTER 4 IPAD INTERFACE ELEMENTS
In the implementation, synthesize the new infoButton and infoPopover properties:
@synthesize infoButton,infoPopover;
Next, you will implement the showInfo method to show the InfoViewController in the


infoPopover :
-(IBAction)showInfo:(id)sender
{
NSLog (@”showInfo”);

// Instatiate Info View Controller
InfoViewController *ivc = [[InfoViewController alloc] init];

UIPopoverController *popover =
[[UIPopoverController alloc] initWithContentViewController:ivc];

[ivc setText:@”If the survey taker refuses, that is okay”];

[ivc release];

// Set the infoPopover property
self.infoPopover = popover;

// Clean up the local popover
[popover release];

[self.infoPopover presentPopoverFromRect:self.infoButton.frame
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];

}
DetailViewController.m
The fi rst thing that you do in this method, after logging the method name, is create an instance of

the
InfoViewController .
Next, you allocate a
UIPopoverController and initialize it by calling the

initWithContentViewController method. You pass the View Controller that you want to display
in the popover as a parameter to this method. Next, you set the text that you want to display in the
popover and release the
InfoViewController . You must send the InfoViewController the release
message or you will leak memory. When you pass the View Controller in to the popover in the

initWithContentViewController method, the popover will retain the View Controller.
The next step is to set the
infoPopover property to the new popover that you created in this
method. Then, you can release the local popover.
Finally, you call the
presentPopoverFromRect:inView:permittedArrowDirections:animated:
method to present the popover. The fi rst parameter to this method specifi es the
CGRect structure
from which the popover should emanate. In this example, you use the frame of the info button
CH004.indd 108CH004.indd 108 9/18/10 9:30:35 AM9/18/10 9:30:35 AM

×