I am developing an iphone application,in that app i am showing the client Parking places in different locations on MKMapView. Now I need to use compass mode in MKMapView to show the client parking places in particular direction (SE,SW,NE,NW), for that I run this below code.
-(void)updateHeading:(CLHeading *) newHeading
{
NSLog(#"New magnetic heading: %f", newHeading.magneticHeading);
NSLog(#"New true heading: %f", newHeading.trueHeading);
double rotation = newHeading.magneticHeading * 3.14159/-180;
[mapView setTransform:CGAffineTransformMakeRotation(-rotation)];
[[mapView annotations] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
MKAnnotationView * view = [mapView viewForAnnotation:obj];
[view setTransform:CGAffineTransformMakeRotation(rotation)];
}];
}
Everthing works fine in MKMapView, but my MKMapView shows in reverse order, when the device starts rotating, I am facing this problem in ios5 and ios6 also.
NOTE: when I test this app in America, map shows correctly, while I test the app in my location (India) Map turns into reverse.
`
Thanks in advance for any help.
Is the map intended to be centered on the user while rotating? If so you could just set the MKMapView's userTrackingMode to MKUserTrackingModeFollowWithHeading.
If not then how about telling us what you see in magneticHeading, trueHeading and rotation when things go right and when they go wrong.
Related
How do I hide the mapview when I have an overlay on top of the mapview in iOS7? This snippet of code used to work in iOS6 but when i upgrade my app to iOS7 it cease to work.
NSArray *views = [[[self.mapView subviews] objectAtIndex:0] subviews];
[[views objectAtIndex:0] setHidden:YES];
Any suggestions or feedback?
With what incanus said with MKTileOverlay, it is like this in the view controller:
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *tileTemplate = #"http://tile.stamen.com/watercolor/{z}/{x}/{y}.jpg";
MKTileOverlay *overlay = [[MKTileOverlay alloc] initWithURLTemplate:tileTemplate];
overlay.canReplaceMapContent = YES;
[self.mapView addOverlay:overlay];
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(37.54827, -121.98857)];
self.mapView.delegate = self;
}
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
MKTileOverlayRenderer *renderer = [[MKTileOverlayRenderer alloc] initWithOverlay:overlay];
return renderer;
}
If you need control over how the overlay feeds the data, you need to subclass MKTileOverlay and override loadTileAtPath:result:
-(void)loadTileAtPath:(MKTileOverlayPath)path result:(void (^)(NSData *, NSError *))result
{
NSData *tile = [self someHowGetTileImageIntoNSDataBaseOnPath:path];
if (tile) {
result(tile, nil);
} else {
result(nil, [NSError errorWithDomain: CUSTOM_ERROR_DOMAIN code: 1 userInfo:nil]);
}
}
The MKOverlay protocol requires boundingMapRect:, which should returns MKMapRect for the rectangular region that this overlay covers. However, I personally found that if I override it myself, it voids the prior canReplaceMapContent = YES setting as Apple probably does not like to show a blank gray map. So I just let MKTileMapOverlay handles it instead.
If your overlay is not actually tiles, then MKTileOverlay does not really apply. But I think you probably can fake it but always reporting nil data within loadTileAtPath:result:, and add your real overlay via another overlay. Another option would be just cover the whole world with black polygon overlay, but then the unsuspecting user would possibly be unknowingly streaming more data than he/she likes.
MapKit isn't really designed for direct access to the map view subviews outside of true overlays (e.g. turning off Apple's map underneath).
Two ideas:
Consider using the new iOS 7 MKTileOverlay class along with the canReplaceMapContent property. This has the effect of turning off Apple's underlying map.
Consider a similar but separate library such as the MapBox iOS SDK which can emulate the look of MapKit but has greater flexibility for styling (and also supports back to iOS 5).
I have no idea why you would want to do it but instead of counting the number of subviews, you should just ask the mapView for the number of overlays it has
if ([[mapView overlays] count] > 0)
{
....
}
Having tried many methods I still haven't found a good and full-proof way of preventing the usual "maps" from being shown behind custom map tiles that I am using. Ultimately I want my app to have a map page consisting only of a custom map.
I am really looking for a solution that is pure iOS and doesn't require any 3rd party software but it would appear difficult.
I have tried 3 methods already:
Number 1, hiding the background map via it's view:
NSArray *views = [[[self.mapView subviews] objectAtIndex:0] subviews];
[[views objectAtIndex:0] setHidden:YES];
this however doesn't work on a certain new operating system coming out very soon! The whole screen goes blank. The Apple Developer Forum hasn't provided a solution either
Number 2, Using another blank overlay (e.g. MKCircle) to cover the background map. This works however when scrolling or zooming out quickly, sometimes the overlay flickers off and you can briefly see the background map behind so not ideal.
Number 3, and this is what I have been working on for a few days now is to simply prevent the user from zooming out. Most documented methods tend to use regionDidChangeAnimated or regionWillChangeAnimated, however these do not seem to suddenly stop the map zooming out when pinching - they wait until the pinch movement has finished before taking effect so again it means the background map can be viewed briefly.
So now I am stumped, unless of course I have missed something with these other two methods.
So any help would be much appreciated!
Add this:
-(void)viewDidAppear:(BOOL)animated
{
MKTileOverlay *overlay = [[MKTileOverlay alloc] init];// initWithURLTemplate:tileTemplate];
overlay.canReplaceMapContent = YES;
[map addOverlay:overlay];
overlay = nil;
}
-(void)loadTileAtPath:(MKTileOverlayPath)path result:(void (^)(NSData *, NSError *))result
{
NSData *tile =nil;
}
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay: (id<MKOverlay>)overlay
{
if ([overlay isKindOfClass:[MKTileOverlay class]])
{
MKTileOverlayRenderer *renderer = [[MKTileOverlayRenderer alloc] initWithOverlay:overlay];
[renderer setAlpha:0.5];
return renderer;
}
}
It will replace the map content from the background. It worked very well in my case where I am adding an overlay on the whole map and hiding the real map from the user.
You can't do this in current releases without a third-party library like MapBox. However, the future OS release that you speak of lets you do this.
Based on what I found on this SO question (Touch events on MKMapView's overlays), I have implemented a way to intercept tap gesture on MKPolygon.
It was working fine in our app that was built using Xcode 4.6.3 against iOS 6. However things stopped working when I tried it on iOS 7 devices.
Specifically
CLLocationCoordinate2D coord = [neighborhoodMap_ convertPoint:point
toCoordinateFromView:neighborhoodMap_];
// We get view from MKMapView's viewForOverlay.
MKPolygonView *polygonView = (MKPolygonView*) view;
CGPoint polygonViewPoint = [polygonView pointForMapPoint:mapPoint];
BOOL mapCoordinateIsInPolygon = CGPathContainsPoint(polygonView.path,
NULL,
polygonViewPoint,
NO);
For some reason the call to CGPathContainsPoint no longer returns YES even the given coordinates is within the MKPolygonView. Not sure if anyone has hit this problem, but I would appreciate any insights you may have.
Thanks!
Since iOS 7 you need to use the MKOverlayRenderer:
BOOL tapInPolygon = NO;
MKOverlayRenderer * polygonRenderer = [mapView rendererForOverlay:polygonOverlay];
if ( [polygonRenderer isKindOfClass:[MKPolygonRenderer class]]) {
//Convert the point
CLLocationCoordinate2D coordinate = [self.mapView convertPoint:tapPoint
toCoordinateFromView:self.mapView];
MKMapPoint mapPoint = MKMapPointForCoordinate(coordinate);
CGPoint polygonViewPoint = [polygonRenderer pointForMapPoint:mapPoint];
// with iOS 7 you need to invalidate the path, this is not required for iOS 8
[polygonRenderer invalidatePath];
tapInPolygon = CGPathContainsPoint(polygonRenderer.path, NULL, polygonViewPoint, NO);
}
I had the same problem and just reading through the docs I found that MKPolygonView has been deprecated in iOS7 and should use MKPolygonRenderer instead.
I was having the same problem and was able to fix it with a workaround, but it definitely looks like a bug on apple's end. I noticed that the "path" property was not NULL right as the MKpolygonView was created, but was NULL whenever I wanted to reference it. The solution is to add another property to the MKPolygonView subclass as follows:
#property CGPathRef savedPath;
and then you have to assign it when it's not NULL:
polygonOverlay.savedPath = CGPathCreateCopy(polygonOverlay.path);
Then just check against self.savedPath whenever needed. Again this is not supposed to be a permanent solution, but will solve the issue of targeting apps to ios6 on ios7 devices.
I'm a newbie to this and remaking an app. I am trying to use UITapGestureRecognizer. It works in the initial project file but not the new one. The only difference is that the old one uses a navigational controller but mine doesn't.
In the new one the self distance:location to:centre is stuck at 640 no matter where you press on the screen.
Can anyone help? I have no idea why it isn't working.
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
CGPoint location = [recognizer locationInView:[recognizer.view superview]];
CGPoint centre = CGPointMake(512,768 / 2);
NSInteger msg = [self distance:location to:centre];
NSLog(#"location to centre: %d", msg);
if ([self distance:location to:centre] < 330)
The part that looks suspicious to me is [recognizer.view superview].
When the gesture recognizer was added to self.view in a UIViewController that is not inside a container controller (e.g. a Navigation Controller) that view does not have a superview. If you send the superview message to self.view without a container view controller it will return nil.
So your message looked basically like this
CGPoint location = [recognizer locationInView:nil];
This will return the location in the window, which is also a valid CGPoint that tells you were you tapped the screen.
Since this didn't work I guess in [self distance:location to:centre] you do something that does only work with coordinates relative to the view. Maybe it's related to rotation, because the coordinates of the window don't rotate when you rotate the device.
Without knowing your code I'm not sure what the problem is, but it probably doesn't matter.
Just replace [recognizer.view superview] with recognizer.view.
Refer below Link, You may get your answer. It's an example if Gesture Recognition.
http://www.techotopia.com/index.php/An_iPhone_iOS_6_Gesture_Recognition_Tutorial
Okay guys, maybe you can help me out with this one. I'm about ready to pull my hair out.
Recently I decided to upgrade my app and make it look better, and with that I wanted to move it into full support for iPad platforms as well. For a while everything worked great. Just press copy MainWindow.xib for iPad, add the views that I used on the iPhone configurations, and everything should be great, but that didn't work too well. Take a look:
Here is the iPhone screenshot:
Here is the iPad screenshot:
Where's the tab bar? I don't understand! I added the initial view when I was first putting it together, but when I linked all of the IBOutlets to the proper pieces, the tab bar no longer shows up.
Screenshot of IB:
Tab Bar properties:
Tint: A bluish color
Image Tint: A goldish color
Mode: Scale to fill
Tag: 0
User Interaction Enabled: (Checked)
Multiple Touch: (Unchecked)
Alpha: 1
Opaque: (Checked)
Hidden (Unchecked)
Clears Graphic Context: (Checked)
Clip Subviews: (Unchecked)
Autoresize Subviews: (Checked)
Stretching: (x,y,w,h):(0,0,1,1)
The viewController.h file is a delegate for UITabBar, UITextField, and UITextView
ViewDidLoad (bar is the IBOutlet for the tab bar):
- (void)viewDidLoad
{
[super viewDidLoad];
[self playMovieIntro];
NSURL *url = [NSURL URLWithString:#"http://www.faithlifefellowship.us/Audio/Sermons/NewSermonBanner.png"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
if(!image == NULL)
{
NewSermonBanner.image = image;
}
series = [[Series alloc] init];
SeriesName = #"";
NSRange range = [[[UIDevice currentDevice] name] rangeOfString:#"iPad"];
int i = 0;
if(range.location != NSNotFound)
i = 1;
bar.selectedItem = hometab;
//set delegates
[bar setDelegate:self];
[personalName setDelegate:self];
[personalEmail setDelegate:self];
[content setDelegate:self];
[prContent setDelegate:self];
[prName setDelegate:self];
[prEmail setDelegate:self];
}
I'm stumped. If you have any ideas or need any more information, let me know.
Thanks!
I'm going to give you a few things I'm getting in order to fix this. It will be tons easier if you could upload the source code for me/us to download and be able to pinpoint the problem.
Sometimes (I can't remember exactly when) I've had my navigation bar not show up because it was missing a connection.
Make sure you are not hiding the tab bar anywhere in code, though it doesn't seem to be the case since it shows up on iPhone.
Otherwise I'm gonna take a guess and say it's something in the NIB. Here are some things you can try:
Check all your connections to outlets
Make sure your objects in the NIB are of the correct class
Verify that the tab bar's "hidden" property is not check in Interface Builder
Compare and verify all the structure of the NIB file between iPhone and iPad
These are just some ideas :) again if you can post the code it would be fantastic.
Let us know how it goes,
Felipe
I had this problem with a app that support both iPhone and iPad. Make sure 'is initial view controller' is checked for the UITabBarController when you examine the view controller using the object inspector. When you do this, xcode will display a 'inbound' arrow on the left side of the view controller if you're using storyboards.