I'm trying to setup an offline map in an iPhone app, but the result is not very good.
I'm using the route-me framework, I've got an offline file .db (created by tiles2sqlite) and the map view is constrained with coordinates (using setConstraintsSW:NE:).
My problem is appearing when zooming out (pinch gesture), this error message "Zooming will move map out of bounds: no zoom" is always present and it's very difficult to zoom out when you are not near the real center of the map.
Is there a solution to have the same result as in Offmaps (iOS app) where the map has a nice scrollview behavior?
Cheers.
Cyril
I had to edit RMMapView.m source code to make a quick fix. Find - (void)zoomByFactor: (float) zoomFactor near:(CGPoint) center animated:(BOOL)animated method (near line 300). It has constrain logic, I turned it off:
- (void)zoomByFactor: (float) zoomFactor near:(CGPoint) center animated:(BOOL)animated
{
if ( _constrainMovement && false ) // turn constraint checks off
{
//check that bounds after zoom don't exceed map constraints
//the logic is copued from the method zoomByFactor,
float _zoomFactor = [self.contents adjustZoomForBoundingMask:zoomFactor];
float zoomDelta = log2f(_zoomFactor);
...
}
...
}
Now map is zoomed smoothly, but this fix could have side effects.
Instead you can use of setting setConstraintsSW:NE: we can set RMMapview as,
RMDBMapSource *mapSrc = [[[RMDBMapSource alloc] initWithPath:#"mapDB.sqlite"] autorelease];
[[RMMapContents alloc] initWithView:mapView tilesource:mapSrc centerLatLon:mapSrc.centerOfCoverage zoomLevel:17 maxZoomLevel:18 minZoomLevel:15 backgroundImage:image screenScale:10 ];
This will enable your zooming acording to your set parameter
Related
In my project, I have an AGSMapView taking up the screen that starts zoomed out to show the entire world map. I have it set to wrap around horizontally, so it works fine there.
However, vertically I can see an empty gray grid at the top and bottom of the map. The user can also scroll the map and this grid can take up at most half the screen, at any zoom level so long as you're at the edge.
Is there any way to snap the edge of the map to the edge of the view it's embedded in and not show this ugly grid?
You should look into AGSMapView.
maxEnveloppe is what you're looking for :
Limits the amount by which the map can be panned such that its anchor point (typically the center) never goes outside this envelope. By default, this is the full envelope of the basemap layer. If you set a custom extent, the envelope must have the same spatial reference as the map.
By the way, you can easily restyle the grid backgroundColor, gridLineWidth, gridLineColor and gridSize. If you want to remove the grid effect, then you have to set the gridLineWidth to 0.
Referring to forum Click here I found closer solution to this problem which worked for me. I have used method suggested by 'reedhr' which I am copying here.
- (void) removePanGesturesFromMap {
NSMutableArray * mutableGestureRecognizers = [[NSMutableArray alloc] initWithArray:MapView.gestureRecognizers];
NSMutableArray *recognizersToRemove = [[NSMutableArray alloc] init];
for (UIGestureRecognizer * gestureRecognizer in MapView.gestureRecognizers) {
if (![gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]
&& ![gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] ) {
[recognizersToRemove addObject:gestureRecognizer];
}
}
if (recognizersToRemove.count > 0) {
[mutableGestureRecognizers removeObjectsInArray:(NSArray*) recognizersToRemove];
MapView.gestureRecognizers = (NSArray*)mutableGestureRecognizers;
}
}
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 want to show my current location lower in the map (iOS 6 and iOS 7) as per below screen shot to user can see further view [google default app with google map].
Right now, the cursor that shows center in the view as per below image [my app with apple map] .
Therefore the largest part of the screen is used to display what's behind, while it cannot look forward very far.
In the first image and second image, I compare to Google Navigation, which shows the current position much lower in the screen, for about the same rotation angle. I've added some arrows to show what I'm talking about.
i tried below code for set center because i cannot find to set lower.
mapView.userTrackingMode = MKUserTrackingModeFollow;
and also try below method
[mapView setCenterCoordinate:currentLocation.coordinate animated:YES];
Setting layoutMargins on MKMapView works just fine.
According to docs,
The default spacing to use when laying out content in the view.
In iOS 11 and later, use the directionalLayoutMargins property to
specify layout margins instead of this property.
To offset camera's centering point to be centered in bottom half of the MKMapView, just set UIEdgeInsets.top to half of MKMapView's height.
class MapViewController: UIViewController {
#IBOutlet var mapView: MKMapView!
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let layoutMargins = UIEdgeInsets(top: self.mapView.bounds.size.height / 2, left: 0, bottom: 0, right: 0)
self.mapView.layoutMargins = layoutMargins
}
Don't set the userTrackingMode or the map's centerCoordinate.
Instead, you can try pointing the MKMapCamera to a coordinate slightly ahead of the user's in the direction they are heading. This will automatically put the user's location lower on the screen.
Calculating the coordinate "a short distance ahead" is not currently built into the iOS SDK so you'd have to calculate it manually.
One way to do it is using the method shown in:
Calculate new coordinate x meters and y degree away from one coordinate.
Using the coordinateFromCoord:atDistanceKm:atBearingDegrees: method from that answer, you could set the camera like this:
MKMapCamera *cam = [MKMapCamera camera];
CLLocationCoordinate2D coordinateAhead =
[self coordinateFromCoord:currentLocation.coordinate
atDistanceKm:0.15
atBearingDegrees:currentLocation.course];
//adjust distance (0.15 km) as needed
cam.centerCoordinate = coordinateAhead;
cam.heading = currentLocation.course;
cam.pitch = 80; //adjust pitch as needed (0=look straight down)
cam.altitude = 100; //adjust as needed (meters)
[mapView setCamera:cam animated:YES];
Try this with the "City Bicycle Ride", "City Run", or "Freeway Drive" in the simulator.
You may need to adjust some of the numbers to get the perspective you want.
A simple workaround that should work is to make the MKMapView frame bigger than the screen of the device.
Something like:
MapViewHeight = (WindowHeight - desiredOffsetFromBottom)*2
I have a custom UIView. In this view I am overriding drawRect to draw some paths and some text.
When a tap is detected, the view is zooming in
- (void)tapDetected:(UITapGestureRecognizer *)sender {
float zoom = 3.;
sender.view.transform = CGAffineTransformScale(sender.view.transform, zoom, zoom);
...
}
Zoom works OK, but lines and text become pixelate as I zoom in. I want the lines width and the text size to stay the same, i.e. to be re-rasterized, so I insert a setNeedsDisplay at the end of the above method, but this has no effect, don't works.
Any help?
Thank you.
Try changing the contentScale of the layer in question. This has worked for my paths.
I was having similar problems with my map viewer, so i cooked up an isolated demo project. I got very heavy antialiasing when zoomed in. Basically, to rerasterize when zooming in, you have to play with the rasterizationScale like so:
sublayer.rasterizationScale = scale;
sublayer.contentsScale = scale;
Sample project and readme are here: https://bitbucket.org/robvanderveer/scrollviewdemo
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.