By Rupert
Posts tagged iphone
iPhone Note #17: Displaying a custom view controller from a UITextField
Nov 2nd
Problem: I want my textFieldSearchAddress to display a seperate viewcontroller.

Short Answer: Hide the keyboard by using
[textField resignFirstResponder]
then show the view controller.
1. Implement a UITextFieldDelegate.
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{ [textField resignFirstResponder]; [self show]; return NO; }
Be careful with the BOOL return of textFieldShouldBeginEditing. From the docs: “YES if an editing session should be initiated; otherwise, NO to disallow editing.”
2. Show the view controller.
- (IBAction)show{ NSLog(@"show"); AddressViewController *addressViewController = [[AddressViewController alloc] initWithNibName:@"AddressViewController" bundle:nil]; UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:addressViewController]; [self presentModalViewController:nav animated:YES]; [addressViewController release]; [nav release]; }
iPhone Note #16: Creating a MKMapView using IB
Oct 29th
In this tutorial we will be addking MKMapView using IB to a ViewController.
1. XCode -> File -> New Project -> View-based Application.
Name the project “SimpleMapIB”
2. Make sure everything works out accordingly before doing anything. Let’s test from the iPhone Simulator. Click on “Build and Go”. You should see the iPhone Simulator running with a gray background. Bring up the Debugger Console (XCode -> Run -> Console) as well and it should be free from errors.
3. Now double-click on “SimpleMapIBViewController.xib”, it should open in Interface Builder.
4. Drag a UIToolbar to the bottom. We will use the button as a GPS in our next tutorial.
5. Drag MKMapView to the middle of the screen.
6. IB -> save
7. Now we need to reference Mapkit. Go to XCode -> Project -> Edit Active Target “SimpleMapIB”. Click the + icon on the bottom left, choose MapKit.framework, then “Add”.

You should see Mapkit added to the frameworks.

You could also organize XCode’s left panel by dragging “MapKit.framework” to the Frameworks Group.

7. Let’s code SimpleMapIBViewController.h
#import <UIKit/UIKit.h> #import <MapKit/MapKit.h> @interface SimpleMapIBViewController : UIViewController { IBOutlet MKMapView *mapview; } @property(nonatomic, retain) IBOutlet MKMapView *mapview; @end
8. Now back to IB. Click on the “File’s Owner” and you should see your outlets displayed “Connections Inspector”. Drag “mapview” to MKMapView Control.

Note: You can click for a bigger image.
9. Now to set “SimpleMapIBViewController” as the delegate. Click on the MKMapView, it should be highlighted and in the “Connections Inspector” notice the “delegate” come out in the Outlets. Drag it to the “Files Owner” to set “SimpleMapIBViewController” as the delegate.

Note: You can click for a bigger image.
10. Now, let’s test. Hit “Clean All” then “Build and Go”. You should see something like this..

11. Now to test that the delegate is setup accordingly, we can code on the viewDidLoad.
- (void)viewDidLoad { mapview.mapType = MKMapTypeSatellite; [super viewDidLoad]; }
12, Now press command-Y for “Build and Debug”. We should see a satellite map instead.

13. That seems a little bit dull, lets add a segmented control so we can switch between maptypes (standard, satellite, hybrid). In IB, drag a UISegmentedControl in the UIToolbar at the bottom. Add another segment, making a total of three. Then change the titles to “Normal”, “Sat”, “Hybrid” respectively.
.
14. Let’s code. In the interface, we need to add a method that would be called by the segmentedControl whened the values changed.
#import <UIKit/UIKit.h> #import <MapKit/MapKit.h> @interface SimpleMapIBViewController : UIViewController { IBOutlet MKMapView *mapview; IBOutlet UISegmentedControl *segmentedControlMapType; } @property(nonatomic, retain) IBOutlet MKMapView *mapview; @property(nonatomic, retain) IBOutlet UISegmentedControl *segmentedControlMapType; - (IBAction)changeMapType: (id)sender; @end
Now in IB, click on the “File’s Owner” and you should see your outlets displayed “Connections Inspector”. Drag “segmentedControlMapType” to the segmented control just like what we did for mapview.
15. In the implementation, we can switch between the segmentIndex and display the corresponding MKMapType.
- (IBAction)changeMapType: (id)sender{ if(segmentedControlMapType.selectedSegmentIndex == 0){ mapview.mapType = MKMapTypeStandard; } else if(segmentedControlMapType.selectedSegmentIndex == 1){ mapview.mapType = MKMapTypeSatellite; } else if(segmentedControlMapType.selectedSegmentIndex == 2){ mapview.mapType = MKMapTypeHybrid; } }
16. Now to hook the IBAction of the UISegmentedControl to the method. In IB, click on the segmented control and in the “Connections Inspector”, drag the “Value Changed” Event to the “File’s Owner” and choose “changeMapType”.
17. Now test in the simulator again and the hybrid button should work.

In my next tutorial, I would be hooking up a GPS button which handles location updates using CoreLocation.
iPhone Note #15: Omnigraffle iPhone Stencils, Screen Mockups via PPT, creating an iPhone interface before actual development
Oct 20th

I can not argue enough how valuable an iphone stencil will be in seeing the overall design/flow of an application. I should have done this a long time ago.
Well, I am also one of those eager developers who dives right into coding and see how it goes. But after having the fundamentals of iphone development, objective-c, and app-store submission, I’m taking on a different approach by creating screen mockups mainly for the following reasons:
1. Reach out quickly to the client.
2. Provides a bird’s eye view of the whole application. Provides alternative screens for a better user experience..
3. A follow up on the screen mockups is a powerpoint with actual links to other slides thus mimicing an iphone interface. Note, it is not a complete replica of the simulator but just enough for decision makers to understand what’s in there.

In powerpoint, you can just quickly overlay a transparent polygon on top of the UIButton then attach a hyperlink to another slide.
Hope this post helps you even if it’s not related to coding. On my next post, which is currently buried in my drafts–hopefully it will not be that long, I learned about integrating with Mobile Advertising Networks.
UPDATED: Bayanihan iPhone Project for Ondoy. Submitted.
Oct 5th
I am a programmer currently in Melbourne, Australia hoping to raise awareness for the victims affected by typhoon Ondoy (Ketsana-international name). Experiencing a flood is not new to me as I was born and raised in Tumana, Marikina, Metro Manila. I was in primary school, when I could vividly remember my mother cooking and serving porridge to typhoon victims as our backyard was called “high ground” since it is near the main road (JP Rizal).
I was in college when Tumana bridge was built and helped me travel from my house to the University. Unfortunately, the river would swell and the flood would swallow the whole bridge after 2-3 days of rain. I called my mother on Sept 27 and was informed the typhoon poured over a whole month of rain in just a few hours! Don’t worry my mother is fine, however, there are those who are unfortunate enough who desperately call for our help. In my small way by making this application, I would like to show my support for them.
I’m almost finished with the Bayanihan iPhone project which I worked on over the weekend. It is a very simple app with scrollable images. The server side is almost finished and would display how many supported/downloaded the application in real time. I am hoping to upload the server side to my Linode hosting in the US asap.
How can you help? I need pictures! Pictures from Tumana would be greatly appreciated, however, if you have other pictures, please do send them as well. I will be bundling 10 pictures inside the application. Please include your name, with subject: BAYANIHAN pix and send the pictures to my email address: rndguzmanjr@gmail.com
Hopefully I can submit the app to Apple within this week or early next week. Afterwards, we wait for the approval process within 2 weeks. Note, the app would be FREE.
UPDATE OCT-05-2009 9:00PM
I took some pictures from facebook and dropped it in the project. It would look something like this when it is finished.
UPDATE OCT-11-2009
- Included proper credits for each photograph.
- Added Admob.
- Created logo, large application icon.
![]()
UPDATE OCT-12-2009
Preparing for appstore submission..
UPDATE OCT-13-2009
Submitted in AppStore. Currently, In-Review.


iPhone Note #14: Drawing a Point, Line, Polygon on top of MKMapview
Oct 2nd
This is an update to iPhone DevNote #13. This post has solved my zooming/panning problem with a CustomView on top of my MKMapView courtesy of http://spitzkoff.com/craig/?p=108 (Craig’s blog).
The trick here is instead of doing the drawing on the drawRect method of the CustomView, we will use Craig’s methodology to use the drawRect method of a custom MKAnnotationView. Note, that he also used an internal view and made clipsToBounds = NO, this way we can draw the whole geometry on top of MKMapView not just a portion of it. The end result is the shape (polygon in this example) is below the added pins.

@interface LinePolygonAnnotationInternalView : UIView { // line view which added this as a subview. LinePolygonAnnotationView* _mainView; } @property (nonatomic, retain) LinePolygonAnnotationView* mainView; @end @implementation LinePolygonAnnotationInternalView @synthesize mainView = _mainView; -(id) init { self = [super init]; self.backgroundColor = [UIColor clearColor]; self.clipsToBounds = NO; return self; } -(void) drawRect:(CGRect) rect { GeometryAnnotation* myAnnotation = (GeometryAnnotation*)self.mainView.annotation; // only draw our lines if we're not int he moddie of a transition and we // acutally have some points to draw. if(!self.hidden && nil != myAnnotation.points && myAnnotation.points.count > 0) { CGContextRef context = UIGraphicsGetCurrentContext(); // Drawing lines with a white stroke color CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0); // Draw them with a 2.0 stroke width so they are a bit more visible. CGContextSetLineWidth(context, 2.0); if(myAnnotation.geometryType == kGeometryTypePolygon){ CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0); } // Draw them with a 2.0 stroke width so they are a bit more visible. CGContextSetLineWidth(context, 2.0); for(int idx = 0; idx < myAnnotation.points.count; idx++) { CLLocation* location = [myAnnotation.points objectAtIndex:idx]; CGPoint point = [self.mainView.mapView convertCoordinate:location.coordinate toPointToView:self]; NSLog(@"Point: %lf, %lf", point.x, point.y); if(idx == 0) { // move to the first point CGContextMoveToPoint(context, point.x, point.y); } else { CGContextAddLineToPoint(context, point.x, point.y); } } if(myAnnotation.geometryType == kGeometryTypeLine){ CGContextStrokePath(context); } else if(myAnnotation.geometryType == kGeometryTypePolygon){ CGContextClosePath(context); CGContextDrawPath(context, kCGPathFillStroke); } } } -(void) dealloc { self.mainView = nil; [super dealloc]; } @end @implementation LinePolygonAnnotationView @synthesize mapView = _mapView; - (id)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.backgroundColor = [UIColor clearColor]; // do not clip the bounds. We need the LinePolygonAnnotationInternalView to be able to render the whole line/polygon, regardless of where the // actual annotation view is displayed. self.clipsToBounds = NO; // create the internal line view that does the rendering of the line. _internalView = [[LinePolygonAnnotationInternalView alloc] init]; _internalView.mainView = self; [self addSubview:_internalView]; } return self; } -(void) setMapView:(MKMapView*) mapView { [_mapView release]; _mapView = [mapView retain]; [self regionChanged]; } -(void) regionChanged { NSLog(@"Region Changed"); // move the internal line view. CGPoint origin = CGPointMake(0, 0); origin = [_mapView convertPoint:origin toView:self]; _internalView.frame = CGRectMake(origin.x, origin.y, _mapView.frame.size.width, _mapView.frame.size.height); [_internalView setNeedsDisplay]; } - (void)dealloc { [_mapView release]; [_internalView release]; [super dealloc]; } @end
I extended the class above to be able to draw both lines and polygons by checking a property (geometryType) of the GeometryAnnotation. If the geometryType is a line, then just stroke the path. However, if the geometryType is a polygon, then close the path and fill it.
if(myAnnotation.geometryType == kGeometryTypeLine){ CGContextStrokePath(context); } else if(myAnnotation.geometryType == kGeometryTypePolygon){ CGContextClosePath(context); CGContextDrawPath(context, kCGPathFillStroke); }
And here is the GeometryAnnotation class. Most of the code is from Craig, i just added the geometryType property:
// Created by Craig on 8/18/09. // Copyright Craig Spitzkoff 2009. All rights reserved. // #import "GeometryAnnotation.h" @implementation GeometryAnnotation @synthesize coordinate = _center; @synthesize points = _points; @synthesize annotationID; @synthesize geometryType; -(id) initWithPoints:(NSArray*) points withGeometry:(GeometryType)geomType { self = [super init]; geometryType = geomType; _points = [[NSMutableArray alloc] initWithArray:points]; // create a unique ID for this line so it can be added to dictionaries by this key. self.annotationID = [NSString stringWithFormat:@"%p", self]; // determine a logical center point for this line based on the middle of the lat/lon extents. double maxLat = -91; double minLat = 91; double maxLon = -181; double minLon = 181; for(CLLocation* currentLocation in _points) { CLLocationCoordinate2D coordinate = currentLocation.coordinate; if(coordinate.latitude > maxLat) maxLat = coordinate.latitude; if(coordinate.latitude < minLat) minLat = coordinate.latitude; if(coordinate.longitude > maxLon) maxLon = coordinate.longitude; if(coordinate.longitude < minLon) minLon = coordinate.longitude; } _span.latitudeDelta = (maxLat + 90) - (minLat + 90); _span.longitudeDelta = (maxLon + 180) - (minLon + 180); // the center point is the average of the max and mins _center.latitude = minLat + _span.latitudeDelta / 2; _center.longitude = minLon + _span.longitudeDelta / 2; NSLog(@"Found center of new Annotation at %lf, %ld", _center.latitude, _center.longitude); return self; } -(MKCoordinateRegion) region { MKCoordinateRegion region; region.center = _center; region.span = _span; return region; } -(void) dealloc { [_points release]; [super dealloc]; } @end
Now that we have a way to draw a line/polygon as a custom MKAnnotationView, we need a custom TouchView (GeometryTouchView) which could accept the touch events.
For example, if the user wants to draw a line geometry, the GeometryTouchView would accept touch events from the user and add a point as a PointAnnotation in the Map. Succeeding points would be added to an array. For every point added, the MKAnnotationView drawRects method connects the points to produce a line. The MKAnnotationView is now added to the map.
Once the geometry is added as an annotation, the custom TouchView is hidden. This way we have access (panning/zooming) to the mapview. If we make a pan or a zoom, the region changes, thus we need to redraw the shape of the annotation again.
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated { if(currentAnnotationView != nil){ NSLog(@"regionWillChangeAnimated"); currentAnnotationView.hidden = YES; } } - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated { if(currentAnnotationView != nil){ NSLog(@"regionDidChangeAnimated"); currentAnnotationView.hidden = NO; [currentAnnotationView regionChanged]; } }
-(void) regionChanged { NSLog(@"Region Changed"); // move the internal line view. CGPoint origin = CGPointMake(0, 0); origin = [_mapView convertPoint:origin toView:self]; _internalView.frame = CGRectMake(origin.x, origin.y, _mapView.frame.size.width, _mapView.frame.size.height); [_internalView setNeedsDisplay]; }
The resulting image is now:

Download the DrawMap.zip code.


Comments