Can't receive touch events from markerInfoWindow UIView in GMSMapView - ios

I have created a custom UIView with XIB and I display this when a user taps on a marker by implementing markerInfoWindow
- (UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(GMSMarker *)marker
{
TESTInfoWindow *view = [[[NSBundle mainBundle] loadNibNamed:#"TESTInfoWindow" owner:self options:nil] objectAtIndex:0];
view.lblTitle.text = [marker title];
return view;
}
Everything works fine, my XIB is displayed and the title populated.
My issue is that I can't get the custom UIView, TESTInfoWindow to respond to touch events. (I want the user to be able to drag the custom info window and the app will respond based on the touchesEnd event.)
I've implemented touchesBegan and touchesMoved in TESTInfoWindow and neither get called:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"DEBUG touchesBegan");
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"DEBUG touchesMoved");
}
I think the GMSMapView is receiving the touches that are ignored by the custom info window view.
How do I get my custom UIView to receive the touches? Any help appreciated.

I just copied the answer for you from this link Adding Click Event on InfoWindow/Marker in Google Maps SDK for native iOS/objective C
1.conform to the GMSMapViewDelegate protocol.
#interface YourViewController () <GMSMapViewDelegate>
// your properties
#end
2.set your mapView_ delegate.
mapView_.delegate = self;
3.implement the GMSMapViewDelegate method
- (void)mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(GMSMarker *)marker {
// your code
NSNumber *number = [marker.userData objectForKey:#"marker_id"];
}
btw, marker.userData is useful. you can set your needed data into it and use it in - mapView:didTapInfoWindowOfMarker:
Eg for set userData on GMSMarker object
GMSMarker *marker = [[GMSMarker alloc] init];
marker.userData = #{#"marker_id":[NSNumber numberWithInt:12]};

Related

Enable UserInteraction to some part of UIViewController

I have been researching about it since last 3 to 4 hours but I didn't get any information. My issue is I want to enable userInteraction to some part of the UIViewController.
Description:
I have a UIViewController. I have added 30 tableviews. I have stored one value in the application. If that value is 1 then I have to enable user interaction for tableview1 only and if the value is 2 then tableview2 only ........etc
. Please let me know if I am not clear. Thank you for spending your valuable time. Thanks in advance
A simple way to do it is to subclass UIView and override - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event.
Return NO for the part of the UIView (represented as ignoreRect in the sample) you want the subviews to ignore touches.
#interface InteractionView ()
#property (nonatomic) CGRect ignoreRect;
#end
#implementation InteractionView
- (void)awakeFromNib {
self.ignoreRect = CGRectMake(0.0f, 0.0f, 300.0f, 300.0f);
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
if (CGRectContainsPoint(self.ignoreRect, point)) {
return NO;
}
return [super pointInside:point withEvent:event];
}
#end
If you need more tweaking for an expected behavior : for exemple return a specific view for a specific zone, return the top view of a specific zone, ... you may use
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (CGRectContainsPoint(self.ignoreRect, point)) {
return nil; // Edit that part if you want to return a chosen view
}
return [super hitTest:point withEvent:event];
}
Another solution without - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event. is to adding UIButton as a subview to the part of UIView you want to close interaction.
for example if you want to close interaction of the bottom half of view.
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0, self.view.frame.size.height*0.5f, self.view.frame.size.width, self.view.frame.size.height*0.5);
[self.view addSubview:button];
since it will get the touch events, half of the view will be closed to user interaction.
EDIT
IBOutletCollection(UITableView) NSArray *allTableViews;// get all your tableviews reference to this array. set tag in interface builder for each array to reach later.
then when you want to enable/disable interaction of related tableview
int tagToOpenInteraction = 1;//or whatever it is
for(UITableView *t in allTableViews)
{
if(t.tag == tagToOpenInteraction)
[t setUserInteractionEnabled:YES];
else
[t setUserInteractionEnabled:NO];
}

iOS MKAnnotationView LongPressGestureRecognizer

Hi to everyone and thanks in advance =)
I have a doubt related with MKMapView and MKAnnotationView. I need to show annotations with custom images on MKMapView. To do this, and following several tutorials and other stackoverflow answers i created my own class. EDAnnotation.h:
#interface EDAnnotation : MKAnnotationView
//#property (nonatomic, strong) UIImageView *imageView;
- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier;
#end
EDAnnotation.m:
#import "EDAnnotation.h"
#implementation EDAnnotation
- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier{
self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
if (self != nil) {
CGRect frame = self.frame;
frame.size = CGSizeMake(15.0, 15.0);
self.frame = frame;
self.backgroundColor = [UIColor clearColor];
self.centerOffset = CGPointMake(-5, -5);
}
return self;
}
-(void) drawRect:(CGRect)rect {
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[style setAlignment:NSTextAlignmentCenter];
[[UIImage imageNamed:#"train4_transparent.png"] drawInRect:CGRectMake(0, 0, 15, 15)];
}
#end
I've added several of this annotations to my map and everything works as expected. Whenever I tap on an image, a bubble showing some information is showed. The problem is that i need to be able to detect long press gesture over one of this annotations (in addition to the tap gesture to show the bubble). To achieve this, i've tried to add UILongGestureRecognizer to almost everything possible:
The UIImageView commented in the class above.
The 'EDAnnotationView' instance retrieved using (EDAnnotation *) [mapView dequeueReusableAnnotationViewWithIdentifier:identifier]; in viewForAnnotation callback. I've even tried to make this instance draggable and to listen for didChangeDragState calls in order to cancel them as soon as MKAnnotationViewDragStateStarting is triggered, but this didn't work as expected too.
Basically what i need is:
if the user presses over the image specified in drawRect method of EDAnnotation the bubble shows.
if the user long presses over the image specified in drawRect method of EDAnnotation receive a callback that lets me add a new MKPointAnnotation to the map.
Thanks in advance for your help =)
The problem could be also that your gestureRecognizer conflicts with the gestureRecognizers in the mapView. This could happen, because the annotationViews are subviews of the mapView.To solve this problem use the UIGestureRecognizerDelegate. When you initialize your gestureRecognizer, set the delegate property to the class where you implement that protocol, more precisely these two methods:
#pragma mark GestureRecognizerDelegate
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
return YES;
}
With easily returning YES in both methods the gestureRecognizer should react. Maybe some other gestureRecognizers from the mapView will now fire their actions too, but unfortunately it's not possible to do the delegation of the mapView's gestureRecognizers.
This workaround helped me, when I was adding a longPressureRecognizer to the mapView. i think it could help you with your issue too.
Did you tried Delegate way of calling annotation?
Create a delegate in Annotation Class
#protocol AnnotationDelegate <NSObject>
#optional
- (void)shouldContinueAnimate;
#end
in implementation file
- (void)shouldContinueAnimate {
//add code for animating
}
Import the delegate where ever required < AnnotationDelegate >
In the image view class you can add both LongPressGestureRecognizer and TapGestureRecognizer for the image.
_longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self
action:#selector(handleLongPressGestureRecognizer:)];
_tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleTapGestureRecognizer:)];
[self.imageView addGestureRecognizer:self.longPressGestureRecognizer];
[self.imageView addGestureRecognizer:self.tapGestureRecognizer];
Handle the method:
- (void)handleTapGestureRecognizer:(UIGestureRecognizer *)sender {
if ([self.delegate respondsToSelector:#selector(shouldContinueAnimate)]) {
[self.delegate shouldContinueAnimate];
}
}
- (void)handleLongPressGestureRecognizer:(UIGestureRecognizer *)sender {
if ([self.delegate respondsToSelector:#selector(shouldContinueAnimate)]) {
[self.delegate shouldContinueAnimate];
}
}
Thanks.

Passing a PanGesture to a subview

I am building a iOS app. I have a UIWebView that is added as a subview to self.view, then another view, which is mapView, added as a subview of the web view. But the mapView is send to the back of the webView. The background of the webView is transparent so that one can see the map.
see the code:
[self.webView addSubview: self.mapView];
[self.webView sendSubviewToBack: self.mapView];
Well what I am trying to do is to pass the gestures of the webView to the mapView so that the user can drag the map.
I have marked the cancelsTouchesInView property to NO for both the webView and the mapView.
I have added a gesture recognizer for the webView. The selector does get called. But what am I supposed to do next?
self.webPanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action: #selector(handleWebPanGesture:)];
[self.webView addGestureRecognizer: self.webPanGesture];
I called the gestureRecognizerShouldBegin method in the webView selector, but it doesn't work.
- ( void ) handleWebPanGesture: ( UIPanGestureRecognizer *)gesture
{
NSLog(#"WebPanGesture recognizer called!");
[self.mapView gestureRecognizerShouldBegin: gesture];
[self panAction: gesture];
self.mapPanGesture = gesture; // the mapPanGesture property is the Gesture recognizer for the map
}
I also call this function
- ( IBAction )panAction:(UIPanGestureRecognizer *)sender {
NSLog(#"panAction called!");
CGPoint move = [sender translationInView:self.webView];
CGPoint newCenter = subViewCenter;
newCenter.x += move.x; newCenter.y += move.y;
self.myMapView.mapView.center = newCenter;
}
but it doesn't make the map draggable, it just moves it.
self.mapPanGesture = gesture //doesn't work as well.
How can I target the actions to the mapView so that the map gets dragged when drag on the webView?
I sure you should use overlays (MKOverlay) on mapView to show content on map. Because this is much easier way to achieve what you need.
Please read this Adding Annotations to a Map
Here I found a way around so do check out this link might be helpful.
In short, webView doesn't handle touchBegan method so u need to subclass that and in touch began method u could pass the following,
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"%#",event);
[super touchesBegan:touches withEvent:event];
[_mapView touchesBegan:touches withEvent:event];
}
or check out for below method,
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *hitView = [super hitTest:point withEvent:event];
// If the hitView is THIS view, return the view that you want to receive the touch instead:
if (hitView == self) {
return otherView;
}
// Else return the hitView (as it could be one of this view's buttons):
return hitView;
}
Above hitTest is with reference to this link.
Hope, this much info is useful to u.

How to add image views to custom annotation view keep pin image on screen and take touches from it?

I have a mapview with pins that show location of photo (coordinates are taken from CoreData) and I need to show photo when pin is selected (using its URL and AFNetworking).
I need to save both pin image and photo image when pin is selected.
If next pin is selected the previous pin is deselected so I remove photo from screen and add another photo of the corresponding pin.
Here is an image to show what particularly I need:
So the pin is on screen and the Photo is on screen.
Problems:
This task is for iPhone so usage of popover is not available.
I need to keep both image of pin and photo, not an image instead of pin. That's why I cannot simply use property 'image' of MKPinAnnotationView class - it sets image
instead of pin.
MK has some private classes for its views so using search over touches is a problem.
Solution for the first and second problem:
I've made a custom class of MKPinAnnotationView which is responsible for adding imageView to MKPinAnnotationView to keep both pin image and photo on screen.
#import "PSMKPinAnnotationView.h"
//my custom annotations, I keep URLs and coordinates of photos there.
#import "PSMapAnnonation.h"
#import "UIImageView+AFNetworking.h" //to display images by URL
#interface PSMKPinAnnotationView ()
#property (nonatomic, strong) UIImageView *imageViewForAnnotaion;
//property in header is:
//#property (nonatomic, getter = isDetailViewHidden) BOOL detailViewHidden;
#end
#implementation PSMKPinAnnotationView
- (BOOL)validAnnotation
{
return [self.annotation isKindOfClass:[PSMapAnnonation class]];
}
- (void)setDetailViewHidden:(BOOL)detailViewHidden
{
//draw image in custom view
if (detailViewHidden==NO)
{
if ([self validAnnotation])
{
self.annotation=(PSMapAnnonation*)self.annotation;
CGRect rect=CGRectMake(0, -35, 30, 30); // y=-35 to make correct offset
self.imageViewForAnnotaion = [[UIImageView alloc] initWithFrame:rect];
[self.imageViewForAnnotaion setImageWithURL:
[(PSMapAnnonation*)self.annotation imageURL]];
[self setClipsToBounds:NO];
[self addSubview:self.imageViewForAnnotaion];
}
}
else if (detailViewHidden==YES)
{
if ([self validAnnotation])
{
[self.imageViewForAnnotaion removeFromSuperview]];
}
}
}
In ViewController where my mapview is in methods of mapView I'm doing this:
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(PSMKPinAnnotationView
*)view
{
if ([view.annotation isKindOfClass:[MKUserLocation class ]]) return;
view.detailViewHidden=NO;
}
-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
if (![view isKindOfClass:[PSMKPinAnnotationView class]]) {
return; //blue point which describes currecnt user position is a view pin too
//and in case of being selected without this check app will crash.
}
PSMKPinAnnotationView *customAnnotationView=(PSMKPinAnnotationView*)view;
[customAnnotationView setDetailViewHidden:YES];
}
So, I've made solution for first two problems:
The result is this:
But the third problem was detected during search over touched views om MKMapView
#pragma mark - Touches
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"touch");
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.mapView];
for (UIView *view in self.mapView.subviews)
{
if ([view isKindOfClass:[PSMKPinAnnotationView class]] &&
CGRectContainsPoint(view.frame, touchLocation))
{
NSLog(#"%#",[view class]);
}
NSLog(#"%#",[view class]);
}
}
Logs show me some Apple's private classes:
- 2014-06-19 11:00:45.428 PhotoShare[881:60b] touch
- 2014-06-19 11:00:45.428 PhotoShare[881:60b] UIView
- 2014-06-19 11:00:45.428 PhotoShare[881:60b] MKAttributionLabel
- 2014-06-19 11:01:47.574 PhotoShare[881:60b] touch
- 2014-06-19 11:01:47.575 PhotoShare[881:60b] UIView
- 2014-06-19 11:01:47.575 PhotoShare[881:60b] MKAttributionLabel
In case of touch on my photo (its image view) my Custom class for view is not detected and some MKAttributionLabel and UIView are shown
Is there any simple solution to do this stuff?
How to connect touches to added imageView and to find them in views?
Logs showed me that MapKit adds some its own views like
MKAttributionLabel(Apple's private classes)?

How to use custom callout for annotation when using Google maps in iOS?

I am using Google Maps in iOS app .So far I am able to show user location on the map. I am trying to use a custom callout when a annotation is clicked.
This is what I have done so far.
1] Created aXIB file and assigned a class name to it of a UIView subclass.
2] Used markerInfoWindow delegate method as below.
- (UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(GMSMarker *)marker
{
CustomGoogleCallOut *view = [[[NSBundle mainBundle]loadNibNamed:#"CustomGoogleCallOut" owner:self options:nil]objectAtIndex:0];
view.callOutImageView.image = [UIImage imageNamed:#"avatar.png"];
view.callOutTitleLabel .text = #"title";
view.callOutUserName.text = #"Mario";
return view;
}
However I am not able to see call out.What am I missing here?
You are missing delegate. in h file
: UIViewController<GMSMapViewDelegate>
in .m file
mapView.delegate = self;

Resources