I have a few annotations added to a MKMapView, and when the user clicks on one of the annotations, it displays a UICalloutView with a right accessory button which adds a UIView to the map, displaying some information about that specific location. This UIView is centred in the superview of the map, and in order to show that the information in that view is relative to the annotation, I would like to shift the visible map rect down (on the y axis), and center it on the x axis so that the annotation is directly under the view.
I am doing the following to centre the annotation, however, I don't know how to move the annotation down on the y axis so that it sits under the added UIView. Please can you tell me how I can do so?
[self.mapView setCenterCoordinate:[annotation coordinate] animated:YES];
If you want to shift the map down so it's centered on a particular coordinate, but shift it down, say, 40%, so you have space for something above it, you could do something like the following:
CLLocationCoordinate2D center = coordinate;
center.latitude -= self.mapView.region.span.latitudeDelta * 0.40;
[self.mapView setCenterCoordinate:center animated:YES];
You can get the size of the information view, then you know how much you want to use the map (based on the difference between its size and the map view size). Now you know the offset, you can calculate the point (in the view coordinate system) that should be moved to the centre so that the annotation is moved down). Then you can use convertPoint:toCoordinateFromView: to find the coordinate for that point to use with setCenterCoordinate:animated:.
Related
I've got an mkmapview which has annotations on it. I want to resize the mapview (by changing it's height constraint's constant from 200 to 400), but I don't want the map's center coordinate to move at all.
Currently, when the map is resized, the center coordinate moves so that it stays in the center of the map (from (x, 100) to (x, 200) if the map height goes from 200 to 400).
It seems the only solution to this is executing code like this:
var coordinate = self.mapView.centerCoordinate
coordinate.latitude += self.mapView.region.span.latitudeDelta * 0.25;
self.mapView.setCenterCoordinate(coordinate, animated: true)
This does work, but the issue I'm encountering is mainly with animation. I want to update the constraint in an animated fashion as well:
mapHeightConstraint.constant = 400
UIView.animateWithDuration(0.35) {
self.view.layoutIfNeeded()
}
This results in the map not being animated regardless of whether I animate the constraint before or after I adjust the center.
I'd like both animations to occur simultaneously and take the same amount of time or find another solution.
I have the following code below that positions my mapView where it shows the coordinates in the center. However, I need it to position the mapView where it will show my coordinates at the top left. The code below is what I am currently using. I am using the category called MKMapView+ZoomLevel.h. If you need any more information please let me know.
[self.mapView setCenterCoordinate:coordinate zoomLevel:level animated:animated];
Get the region with self.mapView.region and find a new coordinate using some simple geometry. Region will give you the center point and the width and height of the view in degrees of latitude and longitude.
From there, you can determine a center coordinate to provide to the map view that will set your original coordinate in the upper left corner.
CLLocationCoordinate2DMake(self.mapView.coordinate.latitude +
self.mapView.region.span.latitudeDelta / 2,
self.mapView.coordinate.longitude +
self.mapView.region.span.longitudeDelta / 2)
I'm drawing a map within a view covering the entire device screen space.
On top of this view is another view occupying the bottom half of the screen. The top view is semi transparent and so the user can see the covered map beneath it.
Within the map I am displaying the user's current location.
The map view is automatically positioning the map such that the user's location is centered within the view - which is therefore the center of the device screen, however the center is also covered by the top view.
However I would like the user's location to be centered within the part of the map view that is not covered by the top view.
The simplest solution is to apply an offset to a coordinate to shift the map a little bit, taking advantage of the span of the region of the MKMapView.
CLLocationCoordinate2D newCenter = userCoordinate;
newCenter.latitude -= _mapView.region.span.latitudeDelta * 0.50;
[self.mapView setCenterCoordinate:newCenter animated:YES];
Value of 0.50 is there just to give you an example. By changing it you can adjust the offset.
You can also take the current center position, convert it to a CGPoint, then add desired offset in pixels to a CGPoint and convert it back to CLLocationCoordinate2D:
UIOffset offset = UIOffsetMake(30.0f, 40.0f);
offset.horizontal
offset.vertical
CGPoint point = [_mapView convertCoordinate:userCoordinate
toPointToView:_mapView];
point.x += offset.horizontal;
point.y += offset.vertical;
CLLocationCoordinate2D newCenter = [_mapView convertPoint:point
toCoordinateFromView:_mapView];
[_mapView setCenterCoordinate:newCenter animated:YES];
Hope it helps.
I have this view with a map that covers most of the screen's area.
On top of the map, I have some images, buttons, text boxes. They're located in the top portion of the map, which I'm calling here "useless map", while the bottom part is for actually viewing the map. This is the "useful map".
By default, the map property centerCoordinate is the center with respect to the full map, as seen as the red circle in the image:
The useful map is marked in green, and I wanted the green circle to be used as a center point.
I can center the map or add a pin, for instance, in that precise point by adding or subtracting from the coordinate's latitude, but the actual value I need to add depends on the zoom level.
Is it possible to change the map center point, or make any changes that can make the map act as if that point (the green circle) is the center?
The purpose of this is that I want to drop a pin at (or move the current pin to) the pseudo-center point (the green one) every time the user drags the map. So to do this, I'd need to get the centerCoordinate (the red one) and then add an offset.
You can add layout margins for the map.
extension MKMapView {
/*
* This is to hide the legal link on the map.
*/
public func centerMapWithBottom(bottomPadding: CGFloat) {
self.layoutMargins = UIEdgeInsets(top: 0, left: 0, bottom: bottomPadding, right: 0)
}
}
This will shift the map center up. Similarly, it can be done for other scenarios as well.
Instead of showing user location for the map just drop an annotation pin at
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = myCoordinate; //CLLocationCoordinate2D myCoordinate
[self.mapView addAnnotation:point];
I really love the way foursquare designed venue detail view. Especially the map with venue location in the "header" of view ... How was it done? Details are obviously some uiscrollview (maybe uitableview?) and behind it (in the header) there is a map so when you scroll up the map is beeing uncovered as the scroll view bounces... does anyone has an idea how to do this?
Here's the way I manage to reproduce it:-
You need a UIViewController with a UIScrollView as its view. Then, the content of the UIView you add to your scrollview should look like this :-
- The frame of the MKMapView have a negative y position. In this case, we can only see 100pts of the maps in the default state (before dragging).
- You need to disable zooming and scrolling on your MKMapView instance.
Then, the trick is to move down the centerCoordinate of the MKMapView when you drag down, and adjust its center position.
For that, we compute how much 1point represent as a delta latitude so that we know how much the center coordinate of the map should be moved when being dragged of x points on the screen :-
- (void)viewDidLoad {
[super viewDidLoad];
UIScrollView* scrollView = (UIScrollView*)self.view;
[scrollView addSubview:contentView];
scrollView.contentSize = contentView.frame.size;
scrollView.delegate = self;
center = CLLocationCoordinate2DMake(43.6010, 7.0774);
mapView.region = MKCoordinateRegionMakeWithDistance(center, 1000, 1000);
mapView.centerCoordinate = center;
//We compute how much latitude represent 1point.
//so that we know how much the center coordinate of the map should be moved
//when being dragged.
CLLocationCoordinate2D referencePosition = [mapView convertPoint:CGPointMake(0, 0) toCoordinateFromView:mapView];
CLLocationCoordinate2D referencePosition2 = [mapView convertPoint:CGPointMake(0, 100) toCoordinateFromView:mapView];
deltaLatFor1px = (referencePosition2.latitude - referencePosition.latitude)/100;
}
Once those properties are initialized, we need to implement the behavior of the UIScrollViewDelegate. When we drag, we convert the move expressed in points to a latitude. And then, we move the center of the map using the half of this value.
- (void)scrollViewDidScroll:(UIScrollView *)theScrollView {
CGFloat y = theScrollView.contentOffset.y;
// did we drag ?
if (y<0) {
//we moved y pixels down, how much latitude is that ?
double deltaLat = y*deltaLatFor1px;
//Move the center coordinate accordingly
CLLocationCoordinate2D newCenter = CLLocationCoordinate2DMake(center.latitude-deltaLat/2, center.longitude);
mapView.centerCoordinate = newCenter;
}
}
You get the same behavior as the foursquare app (but better: in the foursquare app, the maps recenter tends to jump, here, changing the center is done smoothly).
The example above is nice. If you need more help, I think they're using something very similar to RBParallaxTableViewController. https://github.com/Rheeseyb/RBParallaxTableViewController
It's essentially the same effect that Path uses for its header photo.
Yonel's answer is nice, but I found a problem as I have a pin at the center of the map. Because the negative Y, the point is hidden under my UINavigationBar.
Then, I didn't set the Negative Y, and I correct my mapView.frame according the scroll offset.
My mapView is 320 x 160
_mapView.frame = CGRectMake(0, 160, 320, -160+y);
Hope this helps someone.