MKMapView center not correct - ios

I have an app where i'm creating a views hierarchy where i have a mapview and a tableview. The mapview is under the tableview and is visible on the top when the table vertical offset is negative.
The Structure of the view is something like this:
Where the yellow is the map, the green on the top is a navigation bar and green at the bottom is the tableview.
When you scroll the table view the map should show the user location at the center of the visible portion of the map.
The problem i'm experiencing is that when i apply the parallax the map center is not the location i'm setting.
This is a screenshot from a sample project that i did to isolate the problem. The center coordinate is Buckingham Palace.
The orange square is a debug view that is at the center of the mapView (where the center coordinate should be). I'm sure that the parallax effect it's correct.
The structure of my view hierarchy regarding the mapView in the sample project is represented in the following image. The position of the views reflects the screenshot above.
The following code is used to set the frame.origin.y value of the mapContainerView. I'm using the mapContainerView to avoid to touch the frame of the mapView to perform the parallax effect. The mapView is a subview of the mapContainerView (at the begin I was using a translation on the mapView but i changed the code to try to isolate the cause of this problem)
self.mapViewContainer.frame = CGRectMake(0, self.currentY, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame));
if (!CGRectEqualToRect(self.mapViewContainer.bounds, self.mapView.bounds)) {
self.mapView.bounds = CGRectMake(0,
0,
CGRectGetWidth(self.mapViewContainer.bounds),
CGRectGetHeight(self.mapViewContainer.bounds));
self.mapView.center = CGPointMake(CGRectGetMidX(self.mapViewContainer.bounds),
CGRectGetMidY(self.mapViewContainer.bounds));
}
self.squareView.bounds = CGRectMake(0, 0, 22.0f, 22.0f);
self.squareView.center = CGPointMake(CGRectGetMidX(self.mapViewContainer.bounds),
CGRectGetMidY(self.mapViewContainer.bounds));
My guess is that the status bar is doing something to the mapView. If you look to the simulator screenshot you can notice how the center coordinate are exactly located at the center of the vertical space that goes from the status bar to the bottom of the mapView.
If i set the center of the coordinate in the viewDidLoad, after the creation of the map (when it's frame is CGRectZero) the center of the map is correctly in the center of the map.
If i change it later (for example with a timer that, to simulate the location update, sets the same map region that it is set in the viewDidLoad) the map view decide to change the center as showed above.
I can't find any method to disable or change this behaviour. Am I doing something wrong here? I'm working on a workaround but i'm curious to know if someone know what i'm missing here.
This is the code of the sample project i created to reproduce the problem in an isolate scenario. https://gist.github.com/lucabartoletti/a5f103cb74a3edb178d6
Some restriction i have.
The map must be big enough to cover the window frame
The status bar must be visible

Try this:
_mapView.delegate = self;
func mapView(mapView: MKMapView!, didUpdateUserLocation
userLocation: MKUserLocation!) {
mapView.centerCoordinate = userLocation.location.coordinate
}

Related

I want google maps marker to stay in the centre of the map while camera position can change iOS SDK

I am developing an iOS app which uses google maps. I want the marker to stick to the centre of the screen while dragging map or changing camera position. I have implemented below code. It keeps the marker at the centre of the screen, but marker moves when we drag the map and the repositions to centre. I want it to stay at the centre of the screen without moving it.
- (void)mapView:(GMSMapView *)pMapView didChangeCameraPosition:(GMSCameraPosition *)position {
/* move draggable pin */
if (movingMarker) {
CLLocationCoordinate2D location = pMapView.camera.target;
[movingMarker setPosition:location];
return;
}
}
Thanks in advance!
Solution is simple! Just place image view on top of map view, make image view same size (put same constraints, or autoresizing), and set your pin image to image view, set .center contentMode to image view. That's it! You don't have to add a marker to the map view itself. If you want to get pin (map view center) coordinate, use mapView.projection.coordinate(for: CGPoint) of google maps, where you have to pass map view's center point. Good luck!

MapKit - How do I change my custom annotation view's tap "zone"?

I just implemented a custom annotation view and I have a custom callout for it as well. Showing the callout ONLY works when I tap the very top-left corner of my custom annotation view (which is a rectangle). How can I fix it so that I can tap the center of my custom annotation view and it will show the callout ? It is very annoying to have to tap a specific corner of the custom annotation view just to see the callout appear.
I tried to create give my annotation view a centerOffSet value but it did not fix the problem at all... how do I make it so that tapping anywhere on the custom annotation view will bring up the callout view ?
Did you set your custom annotation view's frame correctly? Try set the frame to say CGRectMake(0, 0, 100, 100), and self.backgroundColor to [UIColor grayColor], I think the clickable area will be (100, 100) big shown as gray rectangle.

Setting a MapView's center coordinate does not take into account full size of MapView (off-screen portion)

The Problem
I have a view that includes a full-screen MKMapView. The bottom half of the MapView is covered with a TableView that has translucent cells so that the map shows through.
When I center on an annotation coordinate, the current location for example, the annotation view is blocked by the TableView.
- (void)centerOnCurrentLocation
{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.locationManager.location.coordinate, 50000, 50000);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
}
Attempted Solution
I first tried to programmatically shift the map to offset the center, shifting the annotation up. This approach works if I turn off animation, though it's not a simple solution. Nor do I want to turn off animation.
Instead I thought that if I extend the MapView off the top of the screen by the same height as the TableView the center of the MapView would be exactly where I want it. It doesn't work! When I set the center coordinate on the larger MapView the annotation still appears in the center of the screen, not in the center of the larger MapView. It seems like MKMapView is using the view's visible region when calculating its center.
This is what I would expect to see when I center on current location using the enlarged MapView.
If only MKMapView had a centerOffset property that allowed you to shift the center by some CGPoint.
Does anybody have a simple, elegant solution to offset a MapView's center?
Just to clarify on my comment, you can use setVisibleMapRect: edgePadding: to create the offset you want. You will need to put it in the mapView delegate method regionDidChangeAnimated: this will fire anytime the region changes on your map so you need to wrap your code with a flag to know when to apply the offset or it can be applied multiple times. Here is what you need to do:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{
if (!self.mapInsetsSet) {
self.mapInsetsSet=TRUE;
[self.myMapView setVisibleMapRect:self.myMapView.visibleMapRect edgePadding:UIEdgeInsetsMake(10, 0, 0, 0) animated:YES];
}
}
In the above code, mapInsetsSet is just a bool that you can set elsewhere to control when to apply the offset. Also, you will need to adjust the UIEdgeInsetsMake to the desired offset.

Move a UIView's superview by setting its center property

I have a very strange problem. I trying to rotate and move a UIView's superview manually in viewDidAppear like so:
- (void)viewWillAppear:(BOOL)animated
{
// ...
[self.view.superview setTransform:CGAffineTransformMakeRotation(M_PI/2)];
[self.view.superview setCenter:CGPointMake(100, 200)]; // (100, 200) is toy value
// ...
}
For some reason, the rotation is applied correctly but the superview's center (i.e. position) is not moved at all. I've also tried setting the transform to a CGAffineTransform that's a combination of a rotation + translation (or just a translation alone), and that won't move the superview either.
If it makes a difference, self.view.superview is the top-most view (i.e. self.view.superview.superview is nil).
Am I missing something very simple here?
Edit: nielsbot's comment was correct in that putting it in viewDidLoad worked, but by then, the view has already appeared so there's a flicker where it snaps to the new location. Is there a way around this?
Try setting the bounds of the view so:
[self.view.superview setBounds:CGRectMake(x,y,self.view.superview.width,self.view.superview.height)];
This should move your view to the x,y position you give him
But of course this is not the center
The center just represents a special point that is for example used for rotations

Dragging uiimageview into a "trashcan" while zoomed in on a uiscrollview

Hey everyone. I've searched the web and really haven't found a problem quite like this. My set up is as follows: I am trying to make an app where a user drags uiimageviewss on a uiview inside a uiscrollview (which can zoom in), but also drag the image to a trashcan to be deleted. When the scrollview is zoomed in, the user can still drag because I have subclassed uiimageview and overridden the touchesMoved method. I want the user to be able to drag the uiimageviews to a trashcan in the bottom right corner of the screen. What I implemented already works when the uiscrollview is normal zoom scale, but when you zoom in you cannot drag the image to the trashcan, because well, the trashcan is a subview of the controller's view itself (this was so that it wouldn't zoom with the uiview) and of course is not in the right coordinates of the screen for the uiscrollview.
I've found a view method called ConvertRect that converts a rectangle to the coordinates of whatever view you give to the method, but this doesn't seem to be working. I do a check within each mapimage(the imageview subclass) that checks the frame of the uiimageview intersects the frame of the trashcan. So I try this method before I do that check, but like I said it doesn't seem to be working.
So with all that complicatedness, let me say in a nutshell my problem. I want to drag images over to a trashcan regardless of what zoom level at uiscrollview is at. I can make the trashcan part of the uiscrollview but I need a way to make it keep in the bottom right corner and also not zoom when the uiscrollview does. Any ideas would be so greatly appreciated, thanks guys. :)
I had the exact same challenge.
In can just describe it in short:
When you start dragging the image REMOVE it from the UISCrollView and add it as a subview the the main view of your ViewController.
make sure that the image won't get lost in the process (means: someone still retaining it).
While dragging, constantly check to see if your image entered or left the boundaries of the trash can. you can do it with the method bellow:
-(void) checkForTrashCan
{
CGRect rect = [self.delegate.trashCan convertRect:self.view.frame fromView:self.view.superview];
if ([self.delegate.trashCan rectIntersectBounds:rect])
{
if (NOT self.isInTrashMode)
{
[self enterTrashMode];
}
}
else
{
if (self.isInTrashMode)
{
[self exitTrashMode];
}
}
}
When the method rectIntersectBounds is just a simple extension method for UIView class that i wrote:
-(BOOL) rectIntersectBounds : (CGRect) rect
{
return CGRectIntersectsRect(self.bounds, rect);
}
When the drag ended check if your view is inside the trash can, and act according to the result.

Resources