I have an app with a MKMapView and code that is called each time the map changes locations (in regionDidChangeAnimated). When the app initially loads, regionDidChangeAnimated is called on pans (swipes), pinches, taps and buttons that explicitly update the map coordinates. After loading other views and coming back to the map the regionDidChangeAnimated is only called for taps and the buttons that explicitly update the map. Panning the map and pinches no longer call regionDidChangeAnimated.
I have looked at this stackoverflow post which did not solve this issue. The forum posts on devforums and iphonedevsdk also did not work. Does anyone know what causes this issue? I am not adding any subviews to MKMapView.
I did not want to initially do it this way, but it appears to work with no problems so far (taken from devforums post in question):
Add the UIGestureRecognizerDelegate to your header.
Now add a check for the version number... If we're on iOS 4 we can do this:
if (NSFoundationVersionNumber >= 678.58){
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(pinchGestureCaptured:)];
pinch.delegate = self;
[mapView addGestureRecognizer:pinch];
[pinch release];
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panGestureCaptured:)];
pan.delegate = self;
[mapView addGestureRecognizer:pan];
[pan release];
}
Add the delegate methods to handle the gestures:
#pragma mark -
#pragma mark Gesture Recognizers
- (void)pinchGestureCaptured:(UIPinchGestureRecognizer*)gesture{
if(UIGestureRecognizerStateEnded == gesture.state){
///////////////////[self doWhatYouWouldDoInRegionDidChangeAnimated];
}
}
- (void)panGestureCaptured:(UIPanGestureRecognizer*)gesture{
if(UIGestureRecognizerStateEnded == gesture.state){
///////////////////[self doWhatYouWouldDoInRegionDidChangeAnimated];
}
}
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
return YES;
}
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch: (UITouch *)touch{
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}
Related
I am setting up my app to be compatible with Voice Over feature. I have a graph, I am getting single tap on the -accessibilitiHint(). I need to confirm the user action on double tap which the even can be obtained with accessibilityActivate(). The touch point needs to be retrieved on Single tap.
Now Is there any method to to get user touch point when single tap is performed on my View ?
For Objective C
Step 1:Add TapeGesture Recognizer to your View
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGestureHandler:)];
tapGesture.delegate = self;
[yourView addGestureRecognizer:tapGesture];
Step 2: implement Gesture Delegate Method
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
Step 3: implement Gesture Handler
- (void)tapGestureHandler:(UITapGestureRecognizer *)gesture
{
CGPoint touchPoint = [gesture locationInView:yourView];
}
Is there a way to determine if a MKMapView drag and zoom stops?
Right now I've added an UIPanGestureRecognizer for dragging MKMapView but I'll receive gestureRecognizer.state == UIGestureRecognizerStateEnded immediately when the user lift his finger even though the map is scrolling. What I try to figure out is how to prevent loading server data for my map annotations when the map is still moving and/or the user touches the map one's again to drag the map again? The data load mechanism should be only called when the map stops moving and zooming and is standing still for some predefined time.
This is what I've implement so far:
- (void)viewDidLoad {
...
UIPanGestureRecognizer* panRec = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(didDragMap:)];
[panRec setDelegate:self];
[panRec setDelaysTouchesBegan:YES];
[panRec setDelaysTouchesEnded:YES];
[panRec setCancelsTouchesInView:YES];
[self.mapView addGestureRecognizer:panRec];
}
And the selector method didDragMap:
- (void)didDragMap:(UIGestureRecognizer*)gestureRecognizer {
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
_searchBar.text = #"";
_filtered = NO;
_crosshair.hidden = NO;
[self removeAllAnnotationExceptOfOriginalLocation];
}
else if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
[self performSelector:#selector(delayAddressResolving:) withObject:nil afterDelay:1.0];
}
}
The selector method delayAddressResolving: is loading the needed data from server to display the information for my annotations.
All notes are welcome!
Use the following MKMapViewDelegate methods:
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
These methods are called every time when map region is changing.
determine if MKMapView was dragged/moved
http://developer.apple.com/library/ios/#samplecode/Breadcrumb/Listings/Classes_BreadcrumbViewController_m.html. It may help you
On my mapview I draw polygon overlays that belong to a specific annotation. I want that annotation to be selected when the overlay is tapped. My first attempt was to add a UITapGestureRecognizer to the mapview, test whether the tapped point is inside a polygon and perform [mapView selectAnnotation:myAnnotation] on success. The problem is that after this, the mapview decides there was a tap not on any annotations, so it deselects the annotation again.
My question is how to best prevent this from happening, I don't seem to be able to find a nice solution. What I have tried:
Create a new UIGestureRecognizer subclass that recognizes just taps inside overlays, then iterate through mapView.gestureRecognizers and call requireGestureRecognizerToFail on each. However, the mapview does not expose any recognizers through its property.
Return YES for shouldBeRequiredToFailByGestureRecognizer in my custom recognizer for any other recognizer that isKindOfClass tap recognizer. However, there still seems to be another recognizer that is not passed in there.
Place a transparent view on there and do the polygon check in pointInside:withEvent, but does also blocks any other gestures besides only taps.
EDIT:
After poking around a bit more, I have code that is almost working, of which I know where it goes wrong. I have a custom recognizer as before. In its delegate I do:
- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer
{
[otherGestureRecognizer requireGestureRecognizerToFail:gestureRecognizer]; // can possibly do this in custom recognizer itself instead
return YES;
}
Now taps inside polygons successfully prevent deselection. However, when I then do:
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView
{
// displayRegion is chosen to center annotation
[mapView setRegion:self.displayRegion animated:YES];
}
it breaks again, and the annotation gets deselected again..
It seems we have the same problem ( a little different: i'm tryng to select manually an annotation in a gesture recognizer )
I'm doing so ( and it works, but it seems to complex to me , feel free to ask more if it's not clear ):
i'm working with a long pressure event :
...
_lp1 = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(handleOverlayLp1:)];
((UILongPressGestureRecognizer*)_lp1).minimumPressDuration = 0.05;
_lp1.delegate = self;
[_mapView addGestureRecognizer:_lp1];
...
I collect all gesture recognizers in a global var :
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if (_gestureRecognizers==nil)
_gestureRecognizers = [NSMutableSet set];
[_gestureRecognizers addObject:otherGestureRecognizer];
return YES;
}
// when i recognize gestures, disable everything and call an asyncrhronous task where i re-enable
- (void)handleOverlayLp1:(UIGestureRecognizer*)recognizer
{
// Do Your thing.
if (recognizer.state == UIGestureRecognizerStateBegan)
{
BOOL found=NO;
...
if (found) {
// disable gestures, this forces them to fail, and then reenable in selectOverlayAnnotation that is called asynchronously
for (UIGestureRecognizer *otherRecognizer in _gestureRecognizers) {
otherRecognizer.enabled = NO;
[self performSelector:#selector(selectOverlayAnnotation:) withObject:polyline afterDelay:0.1];
}
}
}
}
- (void)selectOverlayAnnotation: (id<MKAnnotation>) polyline
{
[_mapView selectAnnotation:polyline animated:NO];
for (UIGestureRecognizer *otherRecognizer in _gestureRecognizers) {
otherRecognizer.enabled = YES;
}
}
In my app I have this code:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)recognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isKindOfClass:[UIScrollView class]]){
return YES;
}
else return NO;
}
In this I control if my touch is inside a scrollView or not but now I want to check if the touch is a simple touch or is a swipe gesture, is there a way to detect it?
thanks
The method you written above is UIGestureRecognizerDelegate. This is a delegate method will get called when particular gesture on which you put an observer, gets detected.
In order to identify swipe gesture, you have to add Gesture recognizer to View on which you want to detect as below:
UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
[[self view] addGestureRecognizer:recognizer];
[recognizer release];
You can get gesture detection in method handleSwipeForm:
If you want to get the above delegate to get called then also add this line,
recognizer.delegate = self;
Use UISwipeGestureRecognizer to detect swipe gestures (you can set the swipe direction: UISwipeGestureRecognizer.direction)
And a UITapGestureRecognizer to detect taps (UITapGestureRecognizer.numberOfTapsRequired sets the required number of taps to trigger the recognizer (e. g. for double-taps)
You have to use UISwipeGestureRecognizer in order to detect swipe gestures .
UISwipeGestureRecognizer *swipeGest= [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(SwipeRecognizer:)];
[swipeGest setDirection:(UISwipeGestureRecognizerDirectionRight)];
[[self view] addGestureRecognizer:swipeGest];
swipeGest.delegate = self;
setDirection is used to set the swipe detect direction.
- (void)SwipeRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
}
Here we will be writing the function to do after detecting the swipe gesture.
By default, when swipe a mapkit view, the map moves. This is great.
If I want to move away from the map view and load another viewcontroller's view, how do I accomplish that? I could add a button to do that, but I'd like to use gesture.
Thanks
THE FOLLOWING CODE WORKED:
(1) In the map view controller's header file, I added UIGestureRecognizerDelegate to support its protocol
(2) In map view controller's .m file , I added
- (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
(3) In map view controllers viewDidLoad method I added:
UISwipeGestureRecognizer *leftSwipe =
[[[UISwipeGestureRecognizer alloc]
initWithTarget:self action:#selector(leftSwipeReceiver:)] autorelease];
leftSwipe.direction = UISwipeGestureRecognizerDirectionLeft;
leftSwipe.delegate = self;
[self.view addGestureRecognizer:leftSwipe];
(4) This follow function is called for a left-swipe
- (void)leftSwipeReceiver:(UIGestureRecognizer *)recognizer
{
NSLog(#"leftSwipeReceiver:");
}