Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
How to detect zoom vs drag event on MKMapView.
I want to reload the map in case users want to drag/scroll map to new position. I don't want to reload the Map with zoom in/out event.
I found a solution :(. really simple
1. keep the previous zoom level.
2. in the regionDidChangeAnimated method, get new zoom level of Map and check it with the previous level.
this is my code.
#define MERCATOR_RADIUS 85445659.44705395
#define kVerySmallValue (0.000001)
- (BOOL)compare2Double:(double)first isEqualTo:(double)second {
if(fabs(first - second) < kVerySmallValue)
return YES;
else
return NO;
}
- (double)getZoomLevel
{
static double maxGoogleLevels = -1.0;
if (maxGoogleLevels < 0.0)
maxGoogleLevels = log2(MKMapSizeWorld.width / 256.0);
CLLocationDegrees longitudeDelta = self.mapView.region.span.longitudeDelta;
CGFloat mapWidthInPixels = self.mapView.bounds.size.width;
double zoomScale = longitudeDelta * MERCATOR_RADIUS * M_PI / (180.0 * mapWidthInPixels);
double zoomer = maxGoogleLevels - log2( zoomScale );
if ( zoomer < 0 ) zoomer = 0;
NSLog(#"zoom: %f",zoomer);
return zoomer;
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
double newZoom = [self getZoomLevel];
if ([self compareDouble:newZoom isEqualTo:zoomLevel]) {
NSLog(#"Drag");
}else{
zoomLevel = newZoom;
NSLog(#"Zoom");
}
}
You can find out through the below methods of PangestureRecognizer
- (void)viewDidLoad
{
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(dragMap:)];
panGesture.delegate = self;
[mapView addGestureRecognizer:panGesture];
}
-(void)dragMap:(UIPanGestureRecognizer*) gestureRecognizer
{
if(gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
NSLog(#"The mapView Dragged");
}
}
I understand the problem.
Zoom or drag both the cases call regionWillChangeAnimated and regionDidChangeAnimated you want to differentiate between zoom and drag.
In MapViewControllerDelegate
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
// check mapView.centerCoordinate
// if mapView.centerCoordinate is equal previousCenterCoordinate {
// ZOOM
// } else {
//pinch gesture
//}
}
Update:
I thought my previous example will work. But it did not. This is my second attempt.
Add a method getZoomLevel
#define MERCATOR_OFFSET 268435456
#define MERCATOR_RADIUS 85445659.44705395
- (double) getZoomLevel
{
return 20.00 - log2(self.region.span.longitudeDelta * MERCATOR_RADIUS * M_PI / (180.0 * self.bounds.size.width));
}
In this method, self is mapView. I have a category of MKMapView so it is self in my case.
In MapViewControllerDelegate
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
// zoomLevel = [mapView getZoomLevel]; // or [self getZoomLevel] in your case
// if zoomLevel isEqual previousZoomLevel {
// did drag
// } else {
// did zoom
// previousZoomLevel = zoomLevel
//}
}
Related
I've implemented - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { method to change the default location of userLocation Annotation. Inside this method I've used:
if (annotation==(mapView.userLocation)) {
MKAnnotationView *myAnotation = [[MKAnnotationView alloc] init];
myAnotation.image = self.userPointImage.image;
myAnotation.centerOffset = CGPointMake(0, 250);
return myAnotation;
}
else
{
return nil;
}
Which successfully moves the default userLocation annotation to center bottom. But as I'm also using heading so when move my phone it is still rotating the map from center.
- (void)locationManager:(CLLocationManager *) manager didUpdateHeading:(CLHeading *) newHeading {
[self.mapView setUserTrackingMode:MKUserTrackingModeFollowWithHeading animated:true];
}
But the userLocation annotation is below. So how to do that?
UPDATE I found this question and tried applying it. But as I'm using heading so it crashes the app.
In my didUpdateUserLocation method I added [self moveCenterByOffset:CGPointMake(0, 200) from:userLocation.coordinate]; and this method is as follows:
- (CLLocationCoordinate2D)moveCenterByOffset:(CGPoint)offset from:(CLLocationCoordinate2D)coordinate
{
CGPoint point = [self.mapView convertCoordinate:coordinate toPointToView:self.mapView];
point.x += offset.x;
point.y += offset.y;
CLLocationCoordinate2D center = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
return center;
}
and then in my didUpdateUserLocation method I updated it as: MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([self moveCenterByOffset:CGPointMake(0, -250) from:userLocation.coordinate], 800.0f, 200.0f); and [mapView setRegion:region animated:NO]; as I'm using heading so animation is set to NO. But now as I run the code it starts jerking between center and the new point.
MKCoordinateRegion region = mapClinicsView.region;
set 'region.center'
It will helps you to navigate your map center position
make sure 'region.center' and annotation center latitute and longitute is same
How can I find if the user zoomed in/out on my mapView (GMSMapView)?
I want to do that if the zoom is bigger than 14 all the markers on the map will disappear and if it's smaller all the markers will reload.
How can I do that?
Thanks!
The below code assumes that the view controller has a property of "markerArray" which holds all of the markers.
-(void)mapView:(GMSMapView *)mapView didChangeCameraPosition:(GMSCameraPosition*)position {
int zoom= mapView.camera.zoom;
if (zoom < 14) {
[mapView_ clear];
}
else{
[self displayAllMarkers];
}
}
-(void) displayAllMarkers{
for (BarObject *barMarker in markerArray){
GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = barMarker.location; //
marker.icon = [GMSMarker markerImageWithColor:[UIColor blackColor]];
marker.map = mapView_;
}
}
I also searched for this answer over the summer, and here is what I found and ended up doing:
Create a category on MKMapView:
I named it MKMapView+ZoomLevel
.h
// MKMapView+ZoomLevel.h
#import <MapKit/MapKit.h>
#interface MKMapView (ZoomLevel)
- (int)currentZoomLevel;
#end
.m
// MKMapView+ZoomLevel.m
#import "MKMapView+ZoomLevel.h"
#define MERCATOR_OFFSET 268435456
#define MERCATOR_RADIUS 85445659.44705395
#define MAX_GOOGLE_LEVELS 20
#implementation MKMapView (ZoomLevel)
- (int)currentZoomLevel
{
CLLocationDegrees longitudeDelta = self.region.span.longitudeDelta;
CGFloat mapWidthInPixels = self.bounds.size.width*2;//2 is for retina display
double zoomScale = longitudeDelta * MERCATOR_RADIUS * M_PI / (180.0 * mapWidthInPixels);
double zoomer = MAX_GOOGLE_LEVELS - log2( zoomScale );
if ( zoomer < 0 ) zoomer = 0;
zoomer = round(zoomer);
return (int)zoomer;
}
#end
Then in your view controller:
#import "MKMapView+ZoomLevel.h
// insert logic here
double zoomLevel = [self.mapView currentZoomLevel];
if (zoomLevel > 14 ) {
// add code to hide or resize your annotations
for (id<MKAnnotation> annotation in self.mapView.annotations) {
if (![annotation isKindOfClass:[MKUserLocation class]]) {
[self.mapView removeAnnotation:annotation];
}
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I want to display some images using collection view. What I use scrollview inside cell and image view in scroll view. image are zoom in and zoom out. when cell is reuse new cell scroll view and image view size are same as old which was zoomed.
want when cell reuse scroll view size got default.
how to solve this.
#hello you have to Set gesture in Imageview & usung below methods ,
you can easily set Zoom in & Zoom Out Using Gesture
in ViewDID..
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
scrollViewMain.maximumZoomScale = 5.0;
scrollViewMain.minimumZoomScale = 1.0;
scrollViewMain.clipsToBounds = NO;
scrollViewMain.delegate = self;
UITapGestureRecognizer *tapTwice = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapTwice:)];
// set number of taps required
tapTwice.numberOfTapsRequired = 2;
// now add the gesture recogniser to a view
// this will be the view that recognises the gesture
[scrollViewMain addGestureRecognizer:tapTwice];
}
//------For Zoom IN ScrollView-------------------------------------------------------
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)inScroll {
//self.iPickedPicture.center = ivPicture.center;
return _imgView;
}
- (void)tapOnce:(UIGestureRecognizer *)gesture
{
//on a single tap, call zoomToRect in UIScrollView
if ([scrollViewMain zoomScale] > 1.0)
{
float newScale = 1.0;
CGRect zoomRect = [self zoomToCenter:newScale withCenter:[gesture locationInView:scrollViewMain]];
[scrollViewMain zoomToRect:zoomRect animated:YES];
}
else
{
float newScale = 3.5;
CGRect zoomRect = [self zoomToCenter:newScale withCenter:[gesture locationInView:scrollViewMain]];
[scrollViewMain zoomToRect:zoomRect animated:YES];
}
}
- (void)tapTwice:(UIGestureRecognizer *)gesture
{
//on a double tap, call zoomToRect in UIScrollView
if ([scrollViewMain zoomScale] == 1.0) {
float newScale = [scrollViewMain zoomScale] * 3.5;
CGRect zoomRect = [self zoomToCenter:newScale withCenter:[gesture locationInView:scrollViewMain]];
[scrollViewMain zoomToRect:zoomRect animated:YES];
}else
{
float newScale = 1.0;
CGRect zoomRect = [self zoomToCenter:newScale withCenter:[gesture locationInView:scrollViewMain]];
[scrollViewMain zoomToRect:zoomRect animated:YES];
}
}
- (CGRect)zoomToCenter:(float)scale withCenter:(CGPoint)center {
CGRect zoomRect;
zoomRect.size.height = scrollViewMain.frame.size.height / scale;
zoomRect.size.width = scrollViewMain.frame.size.width / scale;
zoomRect.origin.x = center.x - (zoomRect.size.width / 2.0);
zoomRect.origin.y = center.y - (zoomRect.size.height / 2.0);
return zoomRect;
}
I use MKUserTrackingModeFollowWithHeading so that the map follows the user location and rotates. Problem is zoom level is not sticking. here is my code
-(void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.locMapView.delegate = self;
[self.locMapView setUserTrackingMode:MKUserTrackingModeFollowWithHeading animated:YES];
}
-(void) viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
MKMapPoint pt = MKMapPointForCoordinate(_locMapView.userLocation.coordinate);
double w = MKMapPointsPerMeterAtLatitude(_locMapView.userLocation.coordinate.latitude) * 500;
MKMapRect zoomRect = MKMapRectMake(pt.x - w/2.0, pt.y - w/2.0, w, w);
[_locMapView setVisibleMapRect:zoomRect animated:YES];
}
I tried to set zoom level in viewDidLoad also, not much luck.
How can i make map to stick to zoom level when UserTrackingMode is set to MKUserTrackingModeFollowWithHeading ?
Here's the trick I did to resolve this problem: Set mapView.userTrackingMode = MKUserTrackingModeNone before zoom in/out then set = MKUserTrackingModeFollowWithHeading.
#property (assign, nonatomic) MKUserTrackingMode lastTrackingMode;
- (IBAction)zoomInButtonPressed:(id)sender {
self.mapView.userTrackingMode = MKUserTrackingModeNone;
MKCoordinateRegion newRegion = MKCoordinateRegionMake(self.mapView.region.center,MKCoordinateSpanMake(self.mapView.region.span.latitudeDelta*0.5, self.mapView.region.span.longitudeDelta*0.5));
[self.mapView setRegion:newRegion];
self.mapView.userTrackingMode = self.lastTrackingMode;
}
- (IBAction)zoomOutButtonPressed:(id)sender {
self.mapView.userTrackingMode = MKUserTrackingModeNone;
// Zoom-out code goes here
self.mapView.userTrackingMode = self.lastTrackingMode;
}
I have a MKMapView with a square overlay described as:
CLLocationCoordinate2D coordsBg[5]={
CLLocationCoordinate2DMake(31.750865,35.180882),
CLLocationCoordinate2DMake(31.740331,35.180882),
CLLocationCoordinate2DMake(31.740331,35.165452),
CLLocationCoordinate2DMake(31.750865,35.165452),
CLLocationCoordinate2DMake(31.750865,35.180882)
};
MKPolygon *bg=[MKPolygon polygonWithCoordinates:coordsBg count:5];
[map addOverlay:bg];
I wish to limit the user from scrolling outside of the overlay.
Can I limit the MKMapView scroll view for that? Or there is an other method?
Thanks
Shani
After Few hours of banging my head, I got to this solution that work great for me.
It mixes up :
This post: set the zoom level of an mkmapview
And This link: restrict mkmapview scrolling from #Anna Karenina comment to my question.
And This is my code:
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
{
lastGoodMapRect = mapView.visibleMapRect;
lastGoodRegion = mapView.region;
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
if (manuallyChangingMapRect) {
manuallyChangingMapRect=NO;
return;
}
if( [mapView zoomLevel] > 16 )
{
[mapView setCenterCoordinate:lastGoodRegion.center zoomLevel:16 animated:YES];
}
MKMapRect visibleRect = mapView.visibleMapRect;
MKMapRect OverlayRect = bg.boundingMapRect;
MKMapRect intersectionRect = MKMapRectIntersection(visibleRect,OverlayRect);
//you can change the min and max zoom off course
if(!MKMapRectEqualToRect(visibleRect,intersectionRect)){
if( [mapView zoomLevel] < 15){
[mapView setCenterCoordinate:lastGoodRegion.center zoomLevel:15 animated:YES];
}else if( [mapView zoomLevel] > 16 )
{
[mapView setCenterCoordinate:lastGoodRegion.center zoomLevel:16 animated:YES];
}else{
manuallyChangingMapRect=YES;
[mapView setVisibleMapRect:lastGoodMapRect animated:YES];
}
}
}