I am trying to display a UIImage as a overlay for a map-based iPad application. I attempted to follow the 4 steps to setting a custom overlay defined in Apple's documentation: define the overlay data object, define the object renderer, implement the map view in map view delegate, and add overlay data object to to map view. After attempting to do all these, there is no overlay when I run the simulator. Any advice would be fantastic. My code is as follows
ViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "bjorkOverlay.h"
#import "bjorkOverlayRenderer.h"
#interface TUTViewController : UIViewController <MKMapViewDelegate>
{
CLLocationManager *locationManager;
CLLocation *location;
}
#property (strong, nonatomic) IBOutlet MKMapView *mapView;
#property(nonatomic) MKCoordinateRegion region;
#property (nonatomic, readonly) MKMapRect boundingMapRect;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, readonly) CLLocationCoordinate2D bjorkOverlayCenterPoint;
#property (nonatomic, readonly) MKMapRect bjorkOverlayBoundingMapRect;
#end
ViewController.m
#import "TUTViewController.h"
#import "bjorkOverlay.h"
#import "bjorkOverlayRenderer.h"
#import MapKit;
#interface TUTViewController () <MKMapViewDelegate>
#end
#implementation TUTViewController
- (void)viewDidLoad
{
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
[locationManager startUpdatingLocation];
_mapView.showsUserLocation = YES;
_mapView.delegate = self;
CLLocationCoordinate2D lowerLeftCoord = CLLocationCoordinate2DMake( 45.022943 ,-87.146606);
MKMapPoint lowerLeft = MKMapPointForCoordinate(lowerLeftCoord);
CLLocationCoordinate2D upperRightCoord = CLLocationCoordinate2DMake( 45.048513, -87.124765);
MKMapPoint upperRight = MKMapPointForCoordinate(upperRightCoord);
MKMapRect mapRect = MKMapRectMake(lowerLeft.x, upperRight.y, upperRight.x - lowerLeft.x, lowerLeft.y - upperRight.y);
[self.mapView setVisibleMapRect:mapRect animated:YES];
bjorkOverlay * mapOverlay = [[bjorkOverlay alloc] init];
[_mapView addOverlay:mapOverlay];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay: (id<MKOverlay>)overlay {
MKOverlayRenderer *mapOverlay = [[MKOverlayRenderer alloc] init];
return mapOverlay;
}
// Do any additional setup after loading the view, typically from a nib.
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
bjorkOverlay.h
#import <Foundation/Foundation.h>
#import MapKit;
#interface bjorkOverlay : NSObject <MKOverlay>
+ (id)overlayWithCoordinate:(CLLocationCoordinate2D)coordinate;
#property (nonatomic, assign) CLLocationCoordinate2D bjorkOverlayCenterPoint;
#property (nonatomic) MKMapRect bjorkOverlayBoundingMapRect;
#end
bjorkOverlay.m
#import "bjorkOverlay.h"
#import MapKit;
#implementation bjorkOverlay
+ (id)overlayWithCoordinate:(CLLocationCoordinate2D)coordinate radius:(CLLocationDistance)radius{
bjorkOverlay* overlay = [[bjorkOverlay alloc] init];
overlay.coordinate = coordinate;
return overlay;
}
-(MKMapRect)boundingMapRect{
CLLocationCoordinate2D lowerLeftCoord = CLLocationCoordinate2DMake( 45.022943 ,-87.146606);
MKMapPoint lowerLeft = MKMapPointForCoordinate(lowerLeftCoord);
CLLocationCoordinate2D upperRightCoord = CLLocationCoordinate2DMake( 45.048513, -87.124765);
MKMapPoint upperRight = MKMapPointForCoordinate(upperRightCoord);
MKMapRect mapRect = MKMapRectMake(lowerLeft.x, upperRight.y, upperRight.x - lowerLeft.x, lowerLeft.y - upperRight.y);
return mapRect;
}
- (CLLocationCoordinate2D)bjorkOverlayCenterPoint
{
CLLocationCoordinate2D coord1 = {
45.035728,-87.1356855
};
return coord1;
}
#end
bjorkOverlayRenderer.h
#import <MapKit/MapKit.h>
#interface bjorkOverlayRenderer : MKOverlayRenderer
#end
bjorkOverlayRender.m
#import "bjorkOverlayRenderer.h"
#implementation bjorkOverlayRenderer
- (void)drawMapRect:(MKMapRect)mapRect
zoomScale:(MKZoomScale)zoomScale
inContext:(CGContextRef)ctx
{
UIImage *image = [UIImage imageNamed:#"overlay.png"];
CGImageRef imageReference = image.CGImage;
MKMapRect theMapRect = [self.overlay boundingMapRect];
CGRect theRect = [self rectForMapRect:theMapRect];
CGRect clipRect = [self rectForMapRect:mapRect];
CGContextAddRect(ctx, clipRect);
CGContextClip(ctx);
CGContextDrawImage(ctx, theRect, imageReference);
}
#end
Any advice would be great or if you have seen sample code for MKOverlayRenderer I would appreciate a link. Thanks
Related
I am trying to display some icons on a MKMapView. I have achieved that by using this code:
MapPoint *placeObject = [[MapPoint alloc] initWithName:place.name
address:place.address
coordinate:place.location.coordinate
image:place.customMapPinImage
icon:place.icon
bookmark:place.bookmark
contents_ID:place.contents_ID
contents_lang_MAIN_ID:place.contents_lang_MAIN_ID
contents_lang_ID_ML:place.contents_lang_ID_ML];
[mapView addAnnotation:placeObject];
The problem is that, without changing anything in the code, the size of the icons changed and I don't know why. How can I adjust the size of the icons?
You need to write class annotations
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface Annotation : NSObject <MKAnnotation>
#property (nonatomic) CLLocationCoordinate2D coordinate;
#property (strong, nonatomic) NSString *myTitle;
+ (Annotation *)initAnnotation:(CLLocationCoordinate2D)coordinate title:(NSString *)title;
#end
Implementation
#import "Annotation.h"
#implementation Annotation
+ (Annotation *)initAnnotation:(CLLocationCoordinate2D)coordinate title:(NSString *)title
{
return [[Annotation alloc] initWithAnnotation:coordinate title:title];
}
- (instancetype)initWithAnnotation:(CLLocationCoordinate2D)coordinate title:(NSString *)title
{
self = [super init];
self.coordinate = coordinate;
self.myTitle = title;
return self;
}
#end
ViewController
#import "ViewController.h"
#import <MapKit/MapKit.h>
#import "Annotation.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//set coordinates
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(51.50851, -0.02172);
//add annotation
Annotation *annotation = [Annotation initAnnotation:coordinate title:#"Annotation"];
[self.mapView addAnnotation:annotation];
[self.mapView showAnnotations:#[annotation] animated:YES];
// add circle with radius
MKCircle *circle = [MKCircle circleWithCenterCoordinate:annotation.coordinate radius:10000];
[self.mapView addOverlay:circle];
//add region by coordinates
MKCoordinateRegion region;
region.center.latitude = 51.50851;
region.center.longitude = -0.02172;
// level zoom
region.span.latitudeDelta = 1;
region.span.longitudeDelta = 1;
region = [self.mapView regionThatFits:region];
[self.mapView setRegion:region animated:YES];
}
Do not forget to set the controller as a map delegate, and implement the circle mapping method
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>) overlay{
MKCircleRenderer *circleView = [[MKCircleRenderer alloc] initWithOverlay:overlay];
circleView.fillColor = [[UIColor greenColor] colorWithAlphaComponent:0.4];
return circleView;
}[![enter image description here][1]][1]
Pin appears, and you can adjust its size
https://prntscr.com/lvfjwi
The searchBarBookmarkButtonClicked method isn't firing when I tap on the search bar. I have already added the self.searchBar.deleagate = self; and in my .h file I added the <UISearchBarDelegate>.
.h file:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface ViewController : UIViewController <UISearchBarDelegate,MKMapViewDelegate>
#property (strong, nonatomic) IBOutlet UISearchBar *searchBar;
#property (strong, nonatomic) IBOutlet MKMapView *myMap;
#end
.m file:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.searchBar.delegate = self;
self.myMap.delegate = self;
}
- (void)searchBarBookmarkButtonClicked:(UISearchBar * )searchBar{
NSLog(#"working");
[self.searchBar resignFirstResponder];
NSLog(#"working");
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:self.searchBar.text completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
MKCoordinateRegion region;
CLLocationCoordinate2D newLocation = [placemark.location coordinate];
region.center = [(CLCircularRegion *)placemark.region center];
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
[annotation setCoordinate:newLocation];
[annotation setTitle:self.searchBar.text];
[self.myMap addAnnotation:annotation];
MKMapRect mr = [self.myMap visibleMapRect];
MKMapPoint pt = MKMapPointForCoordinate([annotation coordinate]);
mr.origin.x = pt.x - mr.size.width * 0.5;
mr.origin.y = pt.y -mr.size.width * 0.25;
[self.myMap setVisibleMapRect:mr animated:YES];
}];
}
#end
Make sure you have
All delegate being set properly, this can be done either in code or
in storyboard.
Make use of correct delegate method to capture the
event.
If you think
- (void)searchBarBookmarkButtonClicked:(UISearchBar * )searchBar
then try using the other method which is more straight forward to trigger search
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
Try this UISearchBar delegate method:
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
Thank you #Rahul! Turns out I was using the wrong method!
.h:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface ViewController : UIViewController <UISearchBarDelegate,MKMapViewDelegate>
#property (strong, nonatomic) IBOutlet UISearchBar *searchBar;
#property (strong, nonatomic) IBOutlet MKMapView *myMap;
#end
.m:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.searchBar.delegate = self;
self.myMap.delegate = self;
}
- (void)searchBarBookmarkButtonClicked:(UISearchBar * )searchBar{
[self.searchBar resignFirstResponder];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:self.searchBar.text completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
MKCoordinateRegion region;
CLLocationCoordinate2D newLocation = [placemark.location coordinate];
region.center = [(CLCircularRegion *)placemark.region center];
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
[annotation setCoordinate:newLocation];
[annotation setTitle:self.searchBar.text];
[self.myMap addAnnotation:annotation];
MKMapRect mr = [self.myMap visibleMapRect];
MKMapPoint pt = MKMapPointForCoordinate([annotation coordinate]);
mr.origin.x = pt.x - mr.size.width * 0.5;
mr.origin.y = pt.y -mr.size.width * 0.25;
[self.myMap setVisibleMapRect:mr animated:YES];
}];
}
#end
I'm trying to get my current location to zoom in automatic in mkmapview, but i can't get it to work.
hereĀ“s a bit of code, that i want is to zoom automatic like in Runkeeper.
**the h-file**
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface WalkingTableViewController: UIViewController <MKMapViewDelegate>
#property ( strong, nonatomic) MKMapView *mapView;
#end
**the m-file**
#import "WalkingTableViewController.h"
#interface WalkingTableViewController ()
#end
#implementation WalkingTableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView.showsUserLocation=YES;
self.mapView.delegate = self;
[self.mapView setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
// zoom in on users location (?)
}
#end
You need to set the region, something like:
MKCoordinateRegion region;
region = MKCoordinateRegionMakeWithDistance(_mapView.userLocation.coordinate,10000,10000);
[_mapView setRegion:region animated:YES];
The 10000 is the distance from your center point you want to see in your map.
This should work like a charm
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(CLLocationCoordinate2DMake(your_lat, yout_longitude, 1000.0, 1000.0);
region.span.latitudeDelta = MAX(region.span.latitudeDelta, (coord.latitude - coord.latitude) * 1.05);
region.span.longitudeDelta = MAX(region.span.longitudeDelta, (coord.longitude + coord.longitude) * 1.05);
mapView.region = region;
I'm new to iOS, and it's so different from Android logic that I can't find how to add a marker to a map :-|
I've added a MKMapView to my xib
I've added this code to my .m (trimmed)
#import "AppDelegate.h"
#import <MapKit/MapKit.h>
#interface Dove ()
#property (weak,nonatomic) IBOutlet MKMapView *mappa;
#end
#define METERS_PER_MILE 1609.344
#implementation Dove
- (IBAction)vaiHome:(id)sender {
Index *second = [[Index alloc] initWithNibName:#"Index" bundle:nil];
[self presentViewController:second animated:YES completion:nil];
}
- (void)viewDidLoad
{
[super viewDidLoad];
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = 45.40170;
zoomLocation.longitude= 8.91552;
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, METERS_PER_MILE, METERS_PER_MILE);
[_mappa setRegion:viewRegion animated:YES];
[_mappa regionThatFits:viewRegion];
}
Now, how can I display a pin at that position? It should simple, but I can't find a solution :-|
Also, the map remain in united states but it most go to the marker.
Thanks a lot.
First you have to setup the annotation marker (call this in your viewdidload):
- (void)setupAnnotation
{
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = 45.40170;
zoomLocation.longitude= 8.91552;
NARMapViewAnnotation* annot = [[NARMapViewAnnotation alloc] initWithCoord:zoomLocation];
[_mapView addAnnotation:annot];
}
Then you have to setup the MKMapViewDelegate method:
- (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views
{
MKAnnotationView* annotView = [views objectAtIndex:0];
id<MKAnnotation> mp = [annotView annotation];
MKCoordinateRegion region = [mv regionThatFits:MKCoordinateRegionMakeWithDistance([mp coordinate], REGION_WINDOW, REGION_WINDOW)];
[mv setRegion:region animated:YES];
}
NARMapViewAnnotation:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface NARMapViewAnnotation : NSObject <MKAnnotation>
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
- (id)initWithCoord:(CLLocationCoordinate2D)coord;
#end
#import "NARMapViewAnnotation.h"
#implementation NARMapViewAnnotation
- (id)initWithCoord:(CLLocationCoordinate2D)coord
{
if (self = [super init])
{
_coordinate = coord;
}
return self;
}
#end
Following this tutorial on how to display XML latitude and longitude data as pins on iOS map kit:
http://highoncoding.com/Articles/805_Consuming_XML_Feed_and_Displaying_Public_Information_on_the_MapView_Control.aspx
The sample code provided compiles correctly and displays pins all across the united states. However when I tried to "port" the .xib into my app It pulls up my Mapview and the current users location, but it won't drop any pins/parse the data?
I'm on Day 2 now, its a bit discouraging.
Heres my .m and .h
EleventhViewController.h
// SlideMenu
//
// Created by Kyle Begeman on 1/13/13.
// Copyright (c) 2013 Indee Box LLC. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "ECSlidingViewController.h"
#import "MenuViewController.h"
//#interface EleventhViewController : NSObject <UIApplicationDelegate,MKMapViewDelegate,CLLocationManagerDelegate> {
#interface EleventhViewController : UIViewController <MKMapViewDelegate,CLLocationManagerDelegate,UIApplicationDelegate>
{
IBOutlet MKMapView *mapView;
NSMutableArray *greenCities;
CLLocationManager *locationManager;
}
//-(void) MKMapViewDelegate;
//-(void) CLLocationManagerDelegate;
//#property (nonatomic, weak) id<UIApplicationDelegate> delegate;
//#property (nonatomic, weak) id<MKMapViewDelegate> delegate;
//#property (nonatomic, weak) id<CLLocationManagerDelegate> delegate;
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic,retain) IBOutlet MKMapView *mapView;
#property (nonatomic,retain) NSMutableArray *greenCities;
#property (strong, nonatomic) UIButton *menuBtn;
#property (strong, nonatomic) UIButton *searchBtn;
#end
Heres the .m
//
// EleventhViewController.m
// SlideMenu
//
// Created by Kyle Begeman on 1/13/13.
// Copyright (c) 2013 Indee Box LLC. All rights reserved.
//
#import "EleventhViewController.h"
#import "ECSlidingViewController.h"
#import "MenuViewController.h"
#import "GreenCitiesAppDelegate.h"
#import "GreenCitiesService.h"
#import "GreenCityAnnotation.h"
#import "GreenCityAnnotationView.h"
#import "GreenCity.h"
#interface EleventhViewController ()
//#interface EleventhViewController : UIViewController <MKMapViewDelegate>
#end
#implementation EleventhViewController
#synthesize window=_window,mapView,greenCities;
#synthesize menuBtn;
#synthesize searchBtn;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.mapView.delegate = self;
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[self.mapView setShowsUserLocation:YES];
GreenCitiesService *greenService = [[GreenCitiesService alloc] init];
self.greenCities = [greenService getGreenCities];
[self.window makeKeyAndVisible];
return YES;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.window.layer.shadowOpacity = 0.75f;
self.window.layer.shadowRadius = 10.0f;
self.window.layer.shadowColor = [UIColor blackColor].CGColor;
if (![self.slidingViewController.underLeftViewController isKindOfClass:[MenuViewController class]]) {
self.slidingViewController.underLeftViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Menu"];
}
self.menuBtn = [UIButton buttonWithType:UIButtonTypeCustom];
menuBtn.frame = CGRectMake(9, 23, 40, 30);
[menuBtn setBackgroundImage:[UIImage imageNamed:#"menuButton.png"] forState:UIControlStateNormal];
[menuBtn addTarget:self action:#selector(revealMenu:) forControlEvents:UIControlEventTouchUpInside];
[self.window addSubview:self.menuBtn];
//Top Main Menu Search Button
self.searchBtn = [UIButton buttonWithType:UIButtonTypeCustom];
searchBtn.frame = CGRectMake(275, 25, 40, 30);
[searchBtn setBackgroundImage:[UIImage imageNamed:#"searchButton.png"] forState:UIControlStateNormal];
[searchBtn addTarget:self action:#selector(revealMenu:) forControlEvents:UIControlEventTouchUpInside];
[self.window addSubview:self.searchBtn];
}
- (void)mapView:(MKMapView *)mv didUpdateUserLocation:(MKUserLocation *)userLocation
{
NSLog(#"didUpdateUserLocation fired!");
CLLocationCoordinate2D maxCoord = {-90.0f,-180.0f};
CLLocationCoordinate2D minCoord = {90.0f, 180.0f};
for(int i = 0; i<=[self.greenCities count] - 1;i++)
{
GreenCity *gCity = (GreenCity *) [self.greenCities objectAtIndex:i];
CLLocationCoordinate2D newCoord = { gCity.latitude, gCity.longitude };
if(gCity.longitude > maxCoord.longitude)
{
maxCoord.longitude = gCity.longitude;
}
if(gCity.latitude > maxCoord.latitude)
{
maxCoord.latitude = gCity.latitude;
}
if(gCity.longitude < minCoord.longitude)
{
minCoord.longitude = gCity.longitude;
}
if(gCity.latitude < minCoord.latitude)
{
minCoord.latitude = gCity.latitude;
}
GreenCityAnnotation *annotation = [[GreenCityAnnotation alloc] initWithCoordinate:newCoord title:gCity.name subTitle:gCity.rank];
[mv addAnnotation:annotation];
// [annotation release];
}
MKCoordinateRegion region = {{0.0f, 0.0f}, {0.0f, 0.0f}};
region.center.longitude = (minCoord.longitude + maxCoord.longitude) / 2.0;
region.center.latitude = (minCoord.latitude + maxCoord.latitude) / 2.0;
// calculate the span
region.span.longitudeDelta = maxCoord.longitude - minCoord.longitude;
region.span.latitudeDelta = maxCoord.latitude - minCoord.latitude;
[self.mapView setRegion:region animated:YES];
}
- (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views
{
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)revealMenu:(id)sender
{
[self.slidingViewController anchorTopViewTo:ECRight];
}
#end
My Project is pretty simple, uses a lot of free source code so feel free to download what I've made up to this point, I'm pretty sure it would make a good template/starting base for a lot of you:
https://www.dropbox.com/s/8xxx08zyqpr9i8v/CDF.zip
The method didFinishLauching with options should only be used in the app delegate. You need to move the code from here into viewDidLoad and delete the didFinishLaunching method. Also delete the reference you have to the app delegate from the storyboard xib.
You really want to then set breakpoints in the app and work out where the data load is going wrong.
That fixed it! I moved every piece of executed code under the viewDidLoad! I feel like a noob (which I am) I would up vote you but I don't have enough rep yet. However I keep my connections to the app delegate I imported from the greencities .zip source. Thanks so much. This has however created a new bug in that I can't access my slider menu...fix one problem get another...I really appreciate the direction