In iOS, how to trace the swiped distance in google maps? - iphone

I've an application where I'm using Google maps SDK.
If the user is doing a wild swipe on the map view controller,(say 100miles), Then I want to take the user back to his current location.
How to implement this functionality in maps ?
How to trace the wild swipe which moved the map 100miles on the screen ?
How to know the intensity of the swipe? and how many miles that swipe take you from the current location based on the zoom level?
Thanks in advance!

What do you mean by wild swipe? Move map 100 miles in one swipe? If so, you can add an UIPanGestureRecognizer to the map view,
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:aGMSMapView action:#selector(pan:)];
[aGMSMapView addGestureRecognizer:panRecognizer];
and implement a method to detect if the state of pan gesture is end or not. If so, check the center of the map view to determine how far you moved
-(void)pan:(UIPanGestureRecognizer*) gestureRecognizer
{
if(gestureRecognizer.state == UIGestureRecognizerStateEnded)
{
//get the center of map view, and calculate distance
CGPoint *point = aGMSMapView.center;
CLLocationCoordinate2D coor = [aGMSMapView.projection coordinateForPoint:point];
CLLocation *mapCenter = [[CLLocation alloc]initWithLatitude:coor.latitude longitude:coor.longitude];
CLLocationDistance d = [mapCenter distanceFromLocation:currentLocation];
if (d>= 106900)
{
//move your map view and do whatever you want...
}
}
}

Related

Multitouch with UIPanGestureRecognizer

I'm trying to implement UIPanGestureRecognizer for my view. How do I add multitouch? Below is the code from my view (a subclass of UIView). I would like to be able to know the location and velocity for all of the touches at the same time. The current code only prints out the location and velocity for one touch. Changing the properties minimumNumberOfTouches and maximumNumberOfTouches doesn't work. Thank you very much for your help.
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePanGesture:)];
panGestureRecognizer.cancelsTouchesInView = NO;
[self addGestureRecognizer:panGestureRecognizer];
- (void)handlePanGesture:(UIPanGestureRecognizer *)panGestureRecognizer
{
CGPoint location = [panGestureRecognizer locationInView:panGestureRecognizer.view];
CGPoint velocity = [panGestureRecognizer velocityInView:panGestureRecognizer.view];
NSLog(#"Location: %#", NSStringFromCGPoint(location));
NSLog(#"Velocity: %#", NSStringFromCGPoint(velocity));
}
From the apple documentation for UIGestureRecogniser
(CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(UIView *)view
Parameters
touchIndex
The index of a UITouch object in a private array maintained by the receiver. This touch object represents a touch of the current gesture.
view
A UIView object on which the gesture took place. Specify nil to indicate the window.
Return Value
A point in the local coordinate system of view that identifies the location of the touch. If nil is specified for view, the method returns the touch location in the window’s base coordinate system.
(NSUInteger)numberOfTouches
Return Value
The number of UITouch objects in a private array maintained by the receiver. Each of these objects represents a touch in the current gesture.
Discussion
Using the value returned by this method in a loop, you can ask for the location of individual touches using the locationOfTouch:inView: method.
For example:
(Objective-C)
for(int i=0; i<[panGestureRecogniser numberOfTouches]; i++)
{
CGPoint pt = [panGestureRecogniser locationOfTouch:i inView:self];
}
(Swift)
for i in 0..<panGestureRecogniser.numberOfTouches {
let pt = recognizer.location(ofTouch: i, in: panGestureRecognizer.view)
}
As for velocity I believe there is only one value for it and there is no way to get the velocity of each touch without writing a custom method that calculates the difference between each touch over a series of calls. There is no guarantee that the touches will be at the same index each time however.
Note: As for the minimum and maximum number of touches, these will need to be set accordingly to get multiple touches.

Auto scroll mkmapview when dragging pin

Is there any good code which implements auto scrolling of MKMapView when dragging pin?
The effect I'm trying to achieve is a map scrolling when I drag the pin and reach edges of the map. When I move pin out of the edges I expect scrolling to stop and when I drop it, map shell move until pin reaches center of the screen.
I know how to center map on chosen location, but I'm not really have an idea how to scroll it while dragging pin.
It would really help if someone could just direct me to a logic of the way how to implement it.
MKMapRect mapRect = [self.mapView visibleMapRect];
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(42.777126,-76.113281);
MKMapPoint point = MKMapPointForCoordinate(coordinate);
mapRect.origin.x = point.x - mapRect.size.width * 0.3;
mapRect.origin.y = point.y - mapRect.size.height * 0.70;
[self.mapView setVisibleMapRect:mapRect animated:YES];

Move MKMapView point to pixel coordinates

I have a quick question. I am using a custom view as a callout accessory for my map view. I am having some issues with getting the annotation to move to the right bottom corner of the said view. I am currently trying to get the CGPoint coords of the selected annotation, but beyond that I've drawn a blank Any help would be greatly appreciated.
The current code I'm using (I know it is incorrect is:)
CGPoint bottomLeftPoint = CGPointMake(xOffset,[self.internalAnnotationCallout view].frame.size.height);
CLLocationCoordinate2D bottomLeftCoord = [self.branchLocation convertPoint:bottomLeftPoint toCoordinateFromView:self.branchLocation];
MKCoordinateSpan span = {latitudeDelta: kMapMultiLatDelta, longitudeDelta: kMapMultiLatDelta};
MKCoordinateRegion region = {bottomLeftCoord, span};
[self.branchLocation setRegion:region animated:YES];
//[self.branchLocation setCenterCoordinate:newCenterCoordinate animated:YES];
EDIT:
Ok so I messed around with this a little and was able to to put something together that seems to work, hoping that I now actually understand what you're trying to achieve!
- (void)shiftToCorner{
//ignore "Annotation", this is just my own custom MKAnnotation subclass
Annotation *currentAnnotation = [[mapView selectedAnnotations] objectAtIndex:0];
[mapView setCenterCoordinate:currentAnnotation.coordinate];
CGPoint fakecenter = CGPointMake(20, 20);
CLLocationCoordinate2D coordinate = [mapView convertPoint:fakecenter toCoordinateFromView:mapView];
[mapView setCenterCoordinate:coordinate animated:YES];
}
Let me quickly explain what this does; Let's say you want your annotation to move to a position 20 points in from the right edge and 20 points up from the bottom edge of the map view. If you think about it, if the current annotation is at the center of the map view, then the distance to this point is the same as the distance to (20, 20). This means that we can send our annotation to this point by first centering our map view on the annotation, then animating to (20, 20).

Get coordinates upon mapview gesture

How do I get the latitude and longitude on the point where the user do a longhold(eg 2s)on the mapView.
I chanced upon a similar question : get coordinates on tap in iphone application
But I don't understand how do I go about handling the touch event on the mapView.
What I intent to achieve it to drop a pin annotation to the location, do nesscary reverse geocoding via Google API and display it on the subtitle. So firstly, I would need to get the required coordinates.
Examples would be very much appreciated.
Thanks.
You can convert the coordinates of the touch in the view retrieved from the gesture to gps coordinates like this...
- (void)mapLongPress:(UILongPressGestureRecognizer *)gestureRecognizer{
if(gestureRecognizer.state == UIGestureRecognizerStateBegan){
CGPoint touchLocation = [gestureRecognizer locationInView:mapView];
CLLocationCoordinate2D coordinate;
coordinate = [mapView convertPoint:touchLocation toCoordinateFromView:mapView];
}
}
Note that in my example, I had the gesture applied to the mapView itself. You would have to pass the view to which you applied the gesture to toCoordinateFromView:mapView

Rotate MapView using Compass orientation

Is it possible to have an embedded MKMapView rotate to always face the direction the iPhone is facing? Basically I want to mimic the Map app rotation feature on my own app.
I see that the iPhone SDK does not expose the functionality. However, I wonder if it would work to rotate the entire view using CGAffineTransformMakeRotate. Would it affect tapping and zooming? Is there a better way?
To rotate the mapView but not the annotations you could use the following code to compensate for the maps rotation.
- (void)locationManager:(CLLocationManager *)manager
didUpdateHeading:(CLHeading *)newHeading
{
double rotation = newHeading.magneticHeading * 3.14159 / 180;
CGPoint anchorPoint = CGPointMake(0, -23); // The anchor point for your pin
[mapView setTransform:CGAffineTransformMakeRotation(-rotation)];
[[mapView annotations] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
MKAnnotationView * view = [mapView viewForAnnotation:obj];
[view setTransform:CGAffineTransformMakeRotation(rotation)];
[view setCenterOffset:CGPointApplyAffineTransform(anchorPoint, CGAffineTransformMakeRotation(rotation))];
}];
}
Another sollution is using a new method that has been added in iOS 5 to MKMapView.
Take a look at: http://developer.apple.com/library/ios/#documentation/MapKit/Reference/MKMapView_Class/MKMapView/MKMapView.html
- (void)setUserTrackingMode:(MKUserTrackingMode)mode animated:(BOOL)animated;
I can confirm that it works fine. Here's the code that I'm using:
[mapView setTransform:CGAffineTransformMakeRotation(-1 * currentHeading.magneticHeading * 3.14159 / 180)];
mapView is my MKMapView instance
Simple solution in swift 3.0. Make sure to put the line in mapViewDidFinishLoadingMap or it will ignore it
public func mapViewDidFinishLoadingMap(_ mapView: MKMapView)
{
mapView.setUserTrackingMode(.followWithHeading, animated: false)
}
If you don't want the map to center on the user location you might do something like this
public func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading)
{
if(CLLocationCoordinate2DIsValid(mapView.centerCoordinate))
{
mapView.camera.heading = newHeading.trueHeading
}
}
If you look in the 3.0 iPhone Application Programming Guide under Device Support you'll find information on the magnetometer (aka compass). Once you start getting heading information (through the didUpdateHeading method) you should be able to get the compass data then use that to calculate the proper rotation transform value to apply to the map view.
Not sure if it handles zooming. In the standard map application I've noticed that compass heading tracking stops as soon as you start pinch-zooming.
Also, keep in mind that location directions are in degrees whereas transform rotation angles are in radians.
if you use a navigationVontroller try this:
//For Left button
MKUserTrackingBarButtonItem *buttonItem = [[MKUserTrackingBarButtonItem
alloc]initWithMapView:_mapView];
self.navigationItem.leftBarButtonItem = buttonItem;
// For Right Button
MKUserTrackingBarButtonItem *buttonItem = [[MKUserTrackingBarButtonItem
alloc]initWithMapView:_mapView];
self.navigationItem.rightBarButtonItem = buttonItem;