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?
-
I've edited my answer, now the implementation is perfect ;) – yonel Jul 05 '12 at 08:44
3 Answers
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).

- 4,241
- 10
- 40
- 81

- 7,855
- 2
- 44
- 51
-
wow, this is amazing answer... thanks a lot! sorry for delay when marking it as solved - i was on vacation...anyways ... i actually made it by my own after a while and its similar to your solution...the only difference was that when i scrolled i refreshed whole mapView, which set new visible region (if you scroll a lot the map zoomed) ... i like your solution with just setting new center of the map, its way much more faster then my solution so i will update my code... once again THANKS A LOT ! :) – animal_chin Jul 10 '12 at 21:12
-
Can you explain how you calculate the deltaLatFor1px in the viewDidLoad especially the referencePosition. I get an app crash with the code saying that there is a problem with invalid geo coordinates. Thank you! – MrBr Dec 10 '12 at 17:02
-
Actually what I'm doing is that I create two screen positions, with 100px between them. Then I convert those screen positions to map positions. Then I know how much latitude 100px represent. And then it's easy to know how much latitude is represented by 1px (delta latitude between the 2 screen positions divided by 100). – yonel Dec 11 '12 at 09:04
-
Excellent implementation, thanks! I have some issue, can you help me on this QI? http://stackoverflow.com/q/16123661/1216394 – Paulo Rodrigues Apr 23 '13 at 00:10
-
Thanks a lot sir. This has been very helpful for my project. One comment: Disabling zoom in/out is not necessary as long as you compute delta at the beginning of scrolling and apply delta at the end of scrolling. – L.L. Jun 27 '16 at 13:52
-
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.

- 1,011
- 2
- 12
- 22
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.

- 621
- 7
- 20