How to Move MKCircleView at one position to another position in MKMapView? - ios

I am Declare locations by using MkCircle Now I have to change Circle position one place to another place in MKMapView(Drag & Drop). how can i achieve this. Any help will be appreciated.

First, I'd suggest you have some class property to keep track of the overlay:
#property (nonatomic, weak) MKCircle *overlay;
Then, define a UIPanGestureRecognizer to perform the drag and drop:
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[self.mapView addGestureRecognizer:pan];
To make the gesture cancelable, you should import the following header:
#import <UIKit/UIGestureRecognizerSubclass.h>
And you need to write a handler for this gesture recognizer that adds an overlay for where you dragged and removes the old one (but cancels the gesture if it didn't start over the overlay):
- (void)handlePan:(UIPanGestureRecognizer *)gesture
{
static CGPoint originalPoint;
if (gesture.state == UIGestureRecognizerStateBegan) {
CGPoint point = [gesture locationInView:gesture.view];
CLLocationCoordinate2D tapCoordinate = [self.mapView convertPoint:point toCoordinateFromView:gesture.view];
CLLocation *tapLocation = [[CLLocation alloc] initWithLatitude:tapCoordinate.latitude longitude:tapCoordinate.longitude];
CLLocationCoordinate2D originalCoordinate = [self.overlay coordinate];
CLLocation *originalLocation = [[CLLocation alloc] initWithLatitude:originalCoordinate.latitude longitude:originalCoordinate.longitude];
if ([tapLocation distanceFromLocation:originalLocation] > [self.overlay radius]) {
gesture.state = UIGestureRecognizerStateCancelled;
return;
}
else
originalPoint = [self.mapView convertCoordinate:originalCoordinate toPointToView:gesture.view];
}
if (gesture.state == UIGestureRecognizerStateChanged) {
CGPoint translation = [gesture translationInView:gesture.view];
CGPoint newPoint = CGPointMake(originalPoint.x + translation.x, originalPoint.y + translation.y);
CLLocationCoordinate2D newCoordinate = [self.mapView convertPoint:newPoint toCoordinateFromView:gesture.view];
MKCircle *circle = [MKCircle circleWithCenterCoordinate:newCoordinate radius:[self.overlay radius]];
[self.mapView addOverlay:circle];
[self.mapView removeOverlay:self.overlay];
self.overlay = circle;
}
}
Note, the map's scrollEnabled has to be turned off for this gesture to be recognized.

Related

Gesture recognizer with Voice Over active

I developed an application which allows to the user to draw his finger signature in a canvas.
This feature is implemented using UIPanGestureRecognizer with a specific target action to draw a line in a UIView, but when the “Voice Over” is active the gesture recognizer action is not triggered anymore.
Gesture initialize code
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(pan:)];
pan.maximumNumberOfTouches = pan.minimumNumberOfTouches = 1;
[self addGestureRecognizer:pan];
Gesture action code
- (void)pan:(UIPanGestureRecognizer *)pan {
CGPoint currentPoint = [pan locationInView:self];
CGPoint midPoint = midpoint(previousPoint, currentPoint);
if (pan.state == UIGestureRecognizerStateBegan)
{
[path moveToPoint:currentPoint];
}
else if (pan.state == UIGestureRecognizerStateChanged)
{
[path addQuadCurveToPoint:midPoint controlPoint:previousPoint];
}
previousPoint = currentPoint;
[self setNeedsDisplay];
}
Is there any way to draw a line in a view using gesture with “Voice Over” active?
Thanks and regards!
I resolved my problem setting both isAccessibilityElement and accessibilityTraits properties for UIView canvas:
canvasView.isAccessibilityElement = YES;
canvasView.accessibilityTraits = UIAccessibilityTraitAllowsDirectInteraction;

UITapGestureRecognizer and UIPanGestureRecognizer

I want to create and see a uiimageview when i tap the screen.
Before i lift the finger, i want to move the uiimageview around the screen and the image set only when i take the finger off. Heres what i did:
- (IBAction)tap:(UITapGestureRecognizer *)recognizer {
CGPoint location = [recognizer locationInView:self.view];
UIImageView *circle = [[UIImageView alloc] initWithFrame:CGRectMake(location.x, location.y, 50, 50)];
circle.userInteractionEnabled = YES;
[circle setImage:[UIImage imageNamed:#"monkey_1.png"]];
[self.view addSubview:circle];
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:circle action:nil];
[recognizer requireGestureRecognizerToFail:pan];
CGPoint translation = [pan translationInView:circle];
pan.view.center = CGPointMake(pan.view.center.x + translation.x, pan.view.center.y + translation.y);
[pan setTranslation:CGPointMake(0, 0) inView:self.view];
}
You can do this with just an UIPanGestureRecognizer or an UILongPressGestureRecognizer. In the gesture handling method, check the state property of the recognizer, and show your image when it's UIGestureRecognizerStateEnded (i.e. when the user lifts the finger from the screen). E.g.:
- (void)handleGesture:(UILongPressGestureRecognizer *)recognizer {
if(recognizer.state == UIGestureRecognizerStateEnded) {
// gesture ended: show the image
}
else if(recognizerState == UIGestureRecognizerStateBegan) {
// this code runs when the gesture is started.
}
else if(recognizerState == UIGestureRecognizerStateChanged) {
// gesture is in progress
}
}

Plot pin does not point exact place on MKMapView

- (void)viewDidLoad
{
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(foundTap:)];
tapRecognizer.numberOfTapsRequired = 1;
tapRecognizer.numberOfTouchesRequired = 1;
[self.myMapView addGestureRecognizer:tapRecognizer];
}
-(void)foundTap:(UITapGestureRecognizer *)recognizer
{
CGPoint point = [recognizer locationInView:self.myMapView];
CLLocationCoordinate2D tapPoint = [self.myMapView convertPoint:point toCoordinateFromView:self.view];
MKPointAnnotation *point1 = [[MKPointAnnotation alloc] init];
point1.coordinate = tapPoint;
[self.myMapView addAnnotation:point1];
}
I used above code to make pin point on MKMapView when i choose a place in MKMapView it does not point where i exactly touches.It goes little far where i touches.What is wrong with my code?.any help will be appreciated.thanks in advance.
Try changing the passed-in object to the locationInView: method to self.view:
-(void)foundTap:(UITapGestureRecognizer *)recognizer
{
CGPoint point = [recognizer locationInView:self.view];
CLLocationCoordinate2D tapPoint = [self.myMapView convertPoint:point toCoordinateFromView:self.view];
MKPointAnnotation *point1 = [[MKPointAnnotation alloc] init];
point1.coordinate = tapPoint;
[self.myMapView addAnnotation:point1];
}
I know the other answer is working for you, but I just wanted to show the proper way to use convertPoint:toCoordinateFromView:. Instead of passing it the container view, it should be passed the map view that the point is in:
CLLocationCoordinate2D tapPoint = [self.myMapView convertPoint:point
toCoordinateFromView:self.myMapView];
That saves swapping between views. Here's the full method:
-(void)foundTap:(UITapGestureRecognizer *)recognizer
{
CGPoint point = [recognizer locationInView:self.myMapView];
CLLocationCoordinate2D tapPoint = [self.myMapView convertPoint:point toCoordinateFromView:self.myMapView];
MKPointAnnotation *point1 = [[MKPointAnnotation alloc] init];
point1.coordinate = tapPoint;
[self.myMapView addAnnotation:point1];
}

How to add touch gesture to map but ignore touches on pins and annotations?

I have a mapview that uses MKCircles to display radius information for certain user actions.
What I want to do, is allow the user to dismiss the MKCircle when they touch the map. However, I would like the MKCircle to NOT dismiss should the user touch any of the other pins or the MKCircle itself.
Any ideas?
Here is my current code, which dismisses the MKCircle when any part of the map is touched:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(deactivateAllRadars)];
[tap setCancelsTouchesInView:NO];
[_mapView addGestureRecognizer:tap];
In the deactivateAllRadars method, you can use hitTest:withEvent: to tell whether an MKAnnotationView has been tapped or not.
An example of this is shown in How can I catch tap on MapView and then pass it to default gesture recognizers? (it's the second code sample).
This will let you avoid removing the circle if an annotation has been tapped.
If an annotation has not been tapped, you can then check if an MKCircle was tapped by getting the coordinates of the touch (see How to capture Tap gesture on MKMapView for an example) and seeing if the distance from the touch to the circle's center is greater than its radius.
Note that the deactivateAllRadars should be changed to deactivateAllRadars:(UITapGestureRecognizer *)tgr because it will need information from the associated gesture recognizer. Also be sure to add a colon at the end of the method's selector where you alloc+init tap.
For example:
-(void)deactivateAllRadars:(UITapGestureRecognizer *)tgr
{
CGPoint p = [tgr locationInView:mapView];
UIView *v = [mapView hitTest:p withEvent:nil];
id<MKAnnotation> ann = nil;
if ([v isKindOfClass:[MKAnnotationView class]])
{
//annotation view was tapped, select it...
ann = ((MKAnnotationView *)v).annotation;
[mapView selectAnnotation:ann animated:YES];
}
else
{
//annotation view was not tapped, deselect if some ann is selected...
if (mapView.selectedAnnotations.count != 0)
{
ann = [mapView.selectedAnnotations objectAtIndex:0];
[mapView deselectAnnotation:ann animated:YES];
}
//remove circle overlay if it was not tapped...
if (mapView.overlays.count > 0)
{
CGPoint touchPoint = [tgr locationInView:mapView];
CLLocationCoordinate2D touchMapCoordinate
= [mapView convertPoint:touchPoint toCoordinateFromView:mapView];
CLLocation *touchLocation = [[CLLocation alloc]
initWithLatitude:touchMapCoordinate.latitude
longitude:touchMapCoordinate.longitude];
CLLocation *circleLocation = [[CLLocation alloc]
initWithLatitude:circleCenterLatitude
longitude:circleCenterLongitude];
CLLocationDistance distFromCircleCenter
= [touchLocation distanceFromLocation:circleLocation];
if (distFromCircleCenter > circleRadius)
{
//tap was outside the circle, call removeOverlay...
}
}
}
}
This is my Swift 2.1 compatible version:
func didTapOnMap(recognizer: UITapGestureRecognizer) {
let tapLocation = recognizer.locationInView(self)
if let subview = self.hitTest(tapLocation, withEvent: nil) {
if subview.isKindOfClass(NSClassFromString("MKNewAnnotationContainerView")!) {
print("Tapped out")
}
}
}
MKNewAnnotationContainerView is a private inner class, so you cannot compare directly like:
if subview is MKNewAnnotationContainerView {
}

add mkannotation on touch map

I want to add a mkannotation to my mkmapview when an user taps over the map so they can choose a location.
I've read about the drag&drop but that's a bit annoying if you want to move to the other corner of the city because you have to move step by step the pin.
How can I get the coordinate where a user taps and move my pin there?
Thanks!
Use UITapGestureRecognizer to get the CGPoint and coordinate of tapped point.
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(addPin:)];
[recognizer setNumberOfTapsRequired:1];
[map addGestureRecognizer:recognizer];
[recognizer release];
then add your target action
- (void)addPin:(UITapGestureRecognizer*)recognizer
{
CGPoint tappedPoint = [recognizer locationInView:map];
NSLog(#"Tapped At : %#",NSStringFromCGPoint(tappedPoint));
CLLocationCoordinate2D coord= [map convertPoint:tappedPoint toCoordinateFromView:map];
NSLog(#"lat %f",coord.latitude);
NSLog(#"long %f",coord.longitude);
// add an annotation with coord
}
On ios < 3.2, you can use this snippet:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if ( touch.tapCount == 1 ) {
UITouch *touch = [[event allTouches] anyObject];
if (CGRectContainsPoint([map frame], [touch locationInView:self.view]))
{
CLLocationCoordinate2D coord=
[map convertPoint:tappedPoint toCoordinateFromView:map];
NSLog(#"lat %f",coord.latitude);
NSLog(#"long %f",coord.longitude);
// add an annotation with coord
// or (as example before)
// [self addPin];
}
}
}
it's similar, but don't use UIGestureRecognizer.
Hope this helps.

Resources