iPhone SDK 3 Programming Advanced Mobile Development for Apple iPhone and iPod touc phần 7 pptx

68 309 0
iPhone SDK 3 Programming Advanced Mobile Development for Apple iPhone and iPod touc phần 7 pptx

Đ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

Location Awareness 387 Listing 13.8 shows the implementation of the application delegate class The applicationDidFinishLaunching: method simply creates a view controller of type LocationsViewController and uses it as the root controller for a navigation controller The view of the navigation controller is then added as a subview to the main window and the main window is made visible Listing 13.8 The implementation of the application delegate class used in the tracking application #import "Location3AppDelegate.h" @implementation Location3AppDelegate @synthesize window; - (void)applicationDidFinishLaunching:(UIApplication *)application { window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; ctrl = [[LocationsViewController alloc] initWithNibName:nil bundle:nil]; navCtrl = [[UINavigationController alloc] initWithRootViewController:ctrl]; [window addSubview:navCtrl.view]; [window makeKeyAndVisible]; } - (void)dealloc { [ctrl release]; [navCtrl release]; [window release]; [super dealloc]; } @end Our view controller is declared in Listing 13.9 The view controller adopts the CLLocationManagerDelegate as it will be the delegate of the location manager that it will create It declares two bar buttons for stopping the sampling of movements, navigating to the next recording, and navigating to the previous recording The right bar button will be used for both stopping the sampling of movements and as a “Next” button In addition, the view controller maintains a reference to a web view for visualizing the locations sampled Listing 13.9 The declaration of LocationsViewController view controller class used in the tracking application #import #import @interface LocationsViewController : UIViewController { CLLocationManager *locationMgr; NSUInteger noUpdates; NSMutableArray *locations; UIWebView *webView; 388 iPhone SDK Programming UIBarButtonItem NSUInteger *rightButton, *leftButton; current; } @end Listing 13.10 shows the implementation of the view controller In the initialization method, initWithNibName:bundle:, we create two bar buttons The right button is labelled “Stop” and the left “Previous” The left button is made disabled Listing 13.10 The implementation of LocationsViewController view controller class used in the tracking application #import "LocationsViewController.h" #define NO_OF_LOCATIONS 100 #define MIN_DISTANCE 100 @implementation LocationsViewController - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{ noUpdates++; [locations addObject:newLocation]; self.title = [NSString stringWithFormat:@"Locations: %i", noUpdates]; if(noUpdates == 1){ [self centerMap:0]; } if(noUpdates >= NO_OF_LOCATIONS){ [locationMgr stopUpdatingLocation]; leftButton.enabled = YES; rightButton.title = @"Next"; current = 0; [self centerMap:current]; } } -(void) centerMap:(NSUInteger) index{ CLLocation *loc = [locations objectAtIndex:index]; NSString *js = [NSString stringWithFormat: @"var map = " "new GMap2(document.getElementById(\"map_canvas\"));" "map.setMapType(G_HYBRID_MAP);" "map.setCenter(new GLatLng(%lf, %lf), 18);" "map.panTo(map.getCenter());" "map.openInfoWindow(map.getCenter()," "document.createTextNode(\"Loc: (%i/%i), Time: %@\"));", [loc coordinate].latitude, [loc coordinate].longitude, Location Awareness index+1, [locations count], [loc timestamp]]; [webView stringByEvaluatingJavaScriptFromString:js]; } - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if (self=[super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]){ rightButton = [[UIBarButtonItem alloc] initWithTitle:@"Stop" style:UIBarButtonItemStyleDone target:self action:@selector(stopOrNext)]; self.navigationItem.rightBarButtonItem = rightButton; leftButton = [[UIBarButtonItem alloc] initWithTitle:@"Previous" style:UIBarButtonItemStyleDone target:self action:@selector(prev)]; self.navigationItem.leftBarButtonItem = leftButton; leftButton.enabled = NO; } return self; } -(void)stopOrNext{ if([rightButton.title isEqualToString:@"Stop"] == YES){ [locationMgr stopUpdatingLocation]; leftButton.enabled = YES; rightButton.title = @"Next"; current = 0; [self centerMap:current]; } else if(current < ([locations count]-1)){ [self centerMap:++current]; } } -(void)prev{ if(current > && (current < [locations current = current -1; [self centerMap:current]; } } count])){ - (void)loadView { locations = [[NSMutableArray arrayWithCapacity:10] retain]; locationMgr = [[CLLocationManager alloc] init]; locationMgr.distanceFilter = MIN_DISTANCE; locationMgr.delegate = self; 389 390 iPhone SDK Programming noUpdates = 0; CGRect rectFrame = [UIScreen mainScreen].applicationFrame; webView = [[UIWebView alloc] initWithFrame:rectFrame]; NSString *htmlFilePath = [[NSBundle mainBundle] pathForResource:@"map3" ofType:@"html"]; NSData *data = [NSData dataWithContentsOfFile:htmlFilePath]; [webView loadData:data MIMEType:@"text/html" textEncodingName:@"utf-8" baseURL:[NSURL URLWithString:@"http://maps.google.com/"]]; [locationMgr startUpdatingLocation]; self.view = webView; } - (void)dealloc { [rightButton release]; [leftButton release]; [locationMgr release]; [locations release]; [super dealloc]; } @end The loadView method creates and configures a location manager The distance needed to receive an update is made to be equal to MIN_DISTANCE In addition, a web view is created and initialized with the contents of an HTML file stored in the bundle The file map3.html is shown in Listing 13.11 This file is one of many sample files demonstrating the use of the Google Maps API provided by Google As you will see shortly, we will use JavaScript to modify the appearance of the map dynamically Listing 13.11 The HTML page used for displaying a Google map for the geo-tracking application Geo-tracking Example function initialize() { } Location Awareness 391 On receiving location updates, we store these locations in an array When we have sampled NO_OF_LOCATIONS locations, we enable the left bar button, change the title of the right button to “Next” and point out the first location on the map The method centerMap: is used to display the location on the map The method takes as an input parameter the index of the location in the array of sampled locations It extracts the latitude and longitude information from the location, sets the center of the map to that location, and pans to the center In addition, it opens an information window with the time of the sampling of the location All of this is done in JavaScript such as the one shown below Finally, we execute the JavaScript code using the web view’s method stringByEvaluatingJavaScriptFromString: var map = new GMap2(document.getElementById("map_canvas")); map.setMapType(G_HYBRID_MAP); map.setCenter(new GLatLng(37.331689, -122.030731), 18); map.panTo(map.getCenter()); map.openInfoWindow(map.getCenter(),document.createTextNode("Loc: (1/1), Time: 2008-08-06 19:51:27 -0500")); Figure 13.3 A screenshot of the tracking application while sampling movements 392 iPhone SDK Programming Figure 13.4 A screenshot of the tracking application while viewing a sampled location Figure 13.3 shows a screenshot of the tracking application while sampling movements, and Figure 13.4 shows a screenshot of the tracking application while viewing one of those sampled locations The application poses some ethical (and maybe legal) issues If you find a need to launch this application and hide it in someone’s car or bag, you should think again! Spying is not nice and it may land you in jail Moms, of course, are an exception! One may want to modify the application and add real-time reporting of movements to interested parties This is left to the reader as an exercise 13.5 Working with ZIP Codes The United States Postal Service (USPS) uses a coding system to help in the efficient distribution of mail in the US Each potential recipient of mail is thought to live in a specific zone represented by a Zone Improvement Plan (ZIP) code ZIP codes are, in theory, tied to geographical locations There are various databases available on ZIP codes These databases differ in their accuracy and pricing Databases referring to the latitude and longitude of a given ZIP code can be thought to describe the center of the ZIP code servicing area There are several places where you can buy US ZIP code databases You can even download a recent database for free from the site in [1] Location Awareness 393 The contents of the US ZIP codes file [1] is comma-separated For example, the last few entries in the file are as follows: 89508,Reno,NV,39.5296329,-119.8138027,Washoe 91008,Duarte,CA,34.1394513,-117.9772873,Los Angeles 92058,Oceanside,CA,33.1958696,-117.3794834,San Diego 94505,Discovery Bay,CA,37.9085357,-121.6002291,Contra Costa 95811,Sacramento,CA,38.5815719,-121.4943996,Sacramento In the following, we present the major steps that you can take in order to answer questions like the following: give me all ZIP codes that are within 10 miles of 68508 Create an SQLite zipcodes table To efficiently search, it is advisable to represent your data in a database The following table can be used to store the ZIP code data CREATE TABLE zipcodes ( zipcode int NOT NULL PRIMARY KEY, latitude float(10,8), longitude float(10,8), state varchar(2), city varchar(128), county varchar(128)) The zipcode will be our primary key and for each ZIP code, we have the latitude, longitude, state, city, and county Populate the zipcodes table Populate the table with the ZIP code geographical data obtained from the text file The data is stored in a comma-separated ASCII file Use an NSScanner object for value extraction The extracted tokens of each line are used as input to an INSERT SQL statement Construct an Objective-C class for answering questions After you have produced the database for online use, you need to develop a new class that will answer geographical queries A major query that one would like to ask is: give me all ZIP codes that are within 10 miles of 20007 This query might be implemented with a method having the following signature: -(NSArray*)zipcodesNearLatitude:(float)lat andLongitude:(float) lon withinDistance:(float)distance; Let’s take a look at a possible implementation of the above method The method’s main focus is the execution and the manipulation of results of the following SQL statement: SELECT Z.zipcode FROM zipcodes AS Z WHERE Distance(latitude1, latitude2, Z.latitude, Z.longitude) = MAX_VISIBLE_ROWS){ tableHeight = 225; msgString = @"\n\n\n\n\n\n\n\n\n\n"; } else{ tableHeight = [_data count]*50; for(id value in _data){ [msgString appendString:@"\n\n"]; } if([_data count] == 1){ tableHeight +=5; } if([_data count] == MAX_VISIBLE_ROWS-1){ tableHeight -=15; } } if(self = [super initWithTitle:_title message:msgString delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:nil]){ self.caller = _caller; self.context = _context; self.data = _data; [self prepare]; } 450 iPhone SDK Programming return self; } The method performs three tasks First, it calculates the height of the window by adjusting the dummy alert view message based on the size of the elements to be selected The details of the adjustment are not that important as it is a hack Next, the UIAlertView initializer is called to create the container view Finally, a call to the prepare method is issued in order to create and lay out the table view with the items The prepare method is shown in Listing 16.6 It creates a table view with dimensions to fit an alert view container, enables scrolling only if we have scrollable content, and sets the table view’s delegate and data source to be the TableAlertView instance Listing 16.6 The prepare method for layout of the table view inside an alert view -(void)prepare{ myTableView = [[UITableView alloc] initWithFrame:CGRectMake(15, 35, 255, tableHeight) style:UITableViewStyleGrouped]; myTableView.backgroundColor = [UIColor clearColor]; if([data count] < MAX_VISIBLE_ROWS){ myTableView.scrollEnabled = NO; } myTableView.delegate = self; myTableView.dataSource = self; [self addSubview:myTableView]; } A caller performs two steps in initiating the table alert view similar to the following: TableAlertView *alert = [[[TableAlertView alloc] initWithCaller:self data:data title:@"Did you mean " andContext:nil] autorelease]; [alert show]; The show method of the component is shown below What it does is that it hides itself, schedules a timer, and cascades the show call to the UIAlertView show method The first two steps are not necessary; they just accomplish better user experience vis-à-vis the rendering of the table view -(void)show{ self.hidden = YES; [NSTimer scheduledTimerWithTimeInterval:.5 target:self selector:@selector(myTimer:) userInfo:nil repeats:NO]; [super show]; } Custom UI Components 451 The timer is scheduled to fire in 0.5 seconds and, when it does, it sets the alert view’s hidden property to NO and flashes the table view scroll indicators, but only when we have enough scrollable content The method is shown below -(void)myTimer:(NSTimer*)_timer{ self.hidden = NO; if([data count] > MAX_VISIBLE_ROWS){ [myTableView flashScrollIndicators]; } } Since the TableAlertView is the delegate of the UIAlertView, we define the alertView:clickedButtonAtIndex: method The method simply informs the user that the action has been cancelled Instead of requiring another method in the protocol, we use a negative index of the selected item to signal cancellation of the process - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{ [self.caller didSelectRowAtIndex:-1 withContext:self.context]; } In addition to being a delegate of the alert view, the component is also the data source and delegate for the table view The component defines the tableView:cellForRowAtIndexPath: shown in Listing 16.7 You have already seen plenty of this method! The cell text is retrieved from the description of the corresponding data item provided to the component by the user Listing 16.7 The tableView:cellForRowAtIndexPath: method for the TableAlertView component - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *cellID = @"ABC"; UITableViewCell *cell = (UITableViewCell*) [tableView dequeueReusableCellWithIdentifier:cellID]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID] autorelease]; cell.selectionStyle = UITableViewCellSelectionStyleBlue; } cell.textLabel.text = [[data objectAtIndex:indexPath.row] description]; return cell; } The tableView:didSelectRowAtIndexPath: delegate method simply dismisses the alert view and calls back the caller passing in the index of the selected row and the token (context) This method is shown below 452 iPhone SDK Programming - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ [self dismissWithClickedButtonIndex:0 animated:YES]; [self.caller didSelectRowAtIndex:indexPath.row withContext:self.context]; } For more information, consult the TableAlertView project in the source downloads; this gives a complete application utilizing this component 16.3 Progress Alert View Often, you would like to perform a task, show the user the progress of this task while allowing the user the option of canceling this task Examples include uploading a file for processing or performing image analysis In this section, we will develop a UI component that does just that Figure 16.5 shows how this UI component looks Figure 16.5 The progress alert view UI component Let’s start with the interface Listing 16.8 shows the interface for the ProgressAlertView UI component Custom UI Components Listing 16.8 453 The interface for the ProgressAlertView UI component @interface ProgressAlertView : NSObject { UIProgressView *progressView; UILabel *statusLabel; NSThread *thread; UIAlertView *alertView; SEL task; id delegate; } @property SEL @property(nonatomic, retain) id task; delegate; -(void)start; -(BOOL)isCancelled; -(void)updateProgress:(NSDictionary*)_progressData; @end The interface is simple You create an instance of ProgressAlertView and set its task property to the task you would like to perform, the delegate to your reference, and you send a start message to the component Immediately, the progress alert view appears and your task method is invoked At any time, you can update the progress bar and the message beneath it using the updateProgress: method passing a dictionary with two values: an NSNumber encapsulating a float and a NSString object encapsulating the message Since your task is running on its own thread, the user can interact with the progress alert view If the user taps Cancel, the progress alert view object becomes tainted You can, at any time, check for this state using the isCancelled method Just returning from the task method you’ve supplied, removes the progress alert view Listing 16.9 shows the implementation of the start method It creates the UIAlertView, UIProgressView, and UILabel instances, adds the progress and label views to the alert view, shows the alert view, and starts a new thread Listing 16.9 The start method for the ProgressAlertView UI component -(void)start{ if(thread){ return; } alertView = [[UIAlertView alloc] initWithTitle:nil message:@"\n" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:nil]; progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; 454 iPhone SDK Programming [progressView setBackgroundColor:[UIColor clearColor]]; progressView.frame = CGRectMake(12.0, 20, 260.0, 20.0); [alertView addSubview:progressView]; statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(12.0, 30, 260.0, 20.0)]; statusLabel.backgroundColor = [UIColor clearColor]; statusLabel.textColor = [UIColor whiteColor]; statusLabel.textAlignment = UITextAlignmentCenter; [alertView addSubview:statusLabel]; [alertView show]; thread = [[NSThread alloc] initWithTarget:self selector:@selector(performTask) object:nil]; [thread start]; } The performTask method is the new thread body It creates a new autorelease pool and performs the task method The method is shown below -(void)performTask{ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [delegate performSelector:task]; [self stop]; [pool release]; } The stop method simply dismisses the alert view and is shown below -(void)stop{ [alertView dismissWithClickedButtonIndex:0 animated:YES]; } The updateProgress: method updates the UI You should always perform UI updates from the main thread The method simply routes the call to an internal method that updates the progress bar and the message label It achieves that by sending a performSelectorOnMainThread:withObject:waitUntilDone: message to self The two methods are shown below -(void)safeUpdate:(NSDictionary*)_progressData{ progressView.progress += [[_progressData objectForKey:PROGRESS_PERCENTAGE_KEY] floatValue]; statusLabel.text = [_progressData objectForKey:PROGRESS_MESSAGE_KEY]; } -(void)updateProgress:(NSDictionary*)_progressData{ [self performSelectorOnMainThread:@selector(safeUpdate:) withObject:_progressData waitUntilDone:NO]; } ... 89508,Reno,NV ,39 .529 632 9,-119.8 138 0 27, Washoe 91008,Duarte,CA ,34 . 139 45 13, -1 17. 977 28 73 , Los Angeles 92058,Oceanside,CA ,33 .1958696,-1 17 . 37 94 834 ,San Diego 94505,Discovery Bay,CA , 37 .908 535 7, -121.6002291,Contra... GLatLng ( 37 .33 1689, -122. 030 73 1 ), 18); map.panTo(map.getCenter()); map.openInfoWindow(map.getCenter(),document.createTextNode("Loc: (1/1), Time: 2008-08-06 19:51: 27 -0500")); Figure 13. 3 A screenshot... application while sampling movements 39 2 iPhone SDK Programming Figure 13. 4 A screenshot of the tracking application while viewing a sampled location Figure 13. 3 shows a screenshot of the tracking

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

Từ khóa liên quan

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan