Custom Google Maps Marker for iOS (GMSMarker) - ios

I am trying to create an custom marker for Google Map, but my code is giving me a weird view with space, as the image bellow:
What is that white view? How to remove it? It was supposed to be only the red one!
-(UIView *)mapView:(GMSMapView *)mapView markerInfoContents:(GMSMarker *)marker{
UIView *infoView = [UIView new];
infoView.frame = CGRectMake(0, 0, 290, 192);
// Setting the bg as red just to illustrate
infoView.backgroundColor = [UIColor redColor];
return infoView;
}

I might be a bit rusty but isn't that the wrong function?
There is a markerInfoWindow and a markerInfoContents (which you are using).
The window is the whole thing whereas the contents is a view, which will be placed within the default info window frame
take a look here

The reason behind this white background is that you are using a wrong delegate method. Replace your code with this one:
-(UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(GMSMarker *)marker{
UIView *infoView = [UIView new];
infoView.frame = CGRectMake(0, 0, 290, 192);
// Setting the bg as red just to illustrate
infoView.backgroundColor = [UIColor redColor];
return infoView;
}

Related

Custom didSelectAnnotationView is not scrolling in Map

I have added the custom view in Map when user tap on the Pin maker in the map it will show the uiview ontop of the pin maker but the problem is when i scroll the Map the custom is not scrolling with the map pin please tell me how to resolve this issue.
My code.
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
test = [[UIView alloc]initWithFrame:CGRectMake(view.frame.origin.x - 12.5, view.frame.origin.y - 45, 50, 50)];
test.backgroundColor = [UIColor yellowColor];
[mpview addSubview:test];
}
-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
test.frame = CGRectZero;
}
I have used the above code please tell me how to make the view to scroll with the pin maker in map
Thanks in Advance.
In this case you should add the test not to mapView but to the selected annotation view. Just update the position until it fit your needs.
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
test = [[UIView alloc]initWithFrame:CGRectMake(-10,-25, 50, 50)];
[view addSubview:test];
}
donĀ“t forget to remove the view when you don`t need it anymore.

Custom Callout gesture recognition

I have custom view after select MKAnnotationView and with that i try to add a gesture recognizer like this:
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)selectedAnnotationView {
if([selectedAnnotationView.annotation isKindOfClass:[CustomPinAnnotation class]]) {
CustomPinAnnotation *annotation = selectedAnnotationView.annotation;
[selectedAnnotationView setCalloutOffset:CGPointMake(0,selectedAnnotationView.frame.size.height)];
CalloutView *calloutView = [[CalloutView alloc] initWithFrame:CGRectMake(0, 0, selectedAnnotationView.frame.size.width, selectedAnnotationView.frame.size.height*2)];
[selectedAnnotationView addSubview:calloutView];
[UIView animateWithDuration:annotationAnimationTime animations:^{
[calloutView setFrame:CGRectMake(-expandingAnnotationWidth/8, 0, [calloutView calculateWurstLenghtFromText:selectedAnnotationView.annotation.title], selectedAnnotationView.frame.size.height*2)];
} completion:^(BOOL finished) {
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(calloutTapped:)];
[calloutView addGestureRecognizer:tapGesture];
[calloutView setUserInteractionEnabled:YES];
}];
}
In the screen below you can see how it looks like expanded and not:
The problem is that the gesture recognizer works only on marked area and not on entire callout:
I probably know what's happen - i add subview to MKAnnotation which is to small. But how to fix this? There is another way to draw callout or maybe i can expand tappable area.
1Maybe you could try to change this:
CalloutView *calloutView = [[CalloutView alloc] initWithFrame:CGRectMake(0, 0, selectedAnnotationView.frame.size.width, selectedAnnotationView.frame.size.height*2)];
To this:
CalloutView *calloutView = [[CalloutView alloc] initWithFrame:CGRectMake(0, 0, 150, 150)];
And see if it works, because I have a feeling that annotationView.frame is too small and sets your calloutView just to this small area. If it's hardcoded it might work.
Your annotation's frame is probably too small. Even if you set the callout to be big enough, its parent, the annotation, itself is small. Had the same problem and it's really messy to solve it.
If you don't want to mess with frames and selected states and also because you already are using a custom view which is added, why don't you do the following :
add the custom callout view as a completely new/different annotation/overlay when an annotation is selected ( not as a subview like now )
remove it when your annotation is deselected
You only need to position it correctly and won't even need a gesture recognizer.

Scrolldown a TableView makes the UIImage background move up

Hi here is what I'm trying to do.
I've got a Table View with transparent cell's background.
cell.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"trans.png"]];
And I added to the ViewDidLoad a background image.
- (void)viewDidLoad {
bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
bgView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"homelights.png"]];
[super viewDidLoad];
self.title = #"";
}
So this works fine, I've got a tableView with transparent cells and a background image. Now the plan is when I scroll the TableView down, the image should react and move up.
Any idea how to trigger the scrolldown? Or where to start?
I enabled scrollViewDidScroll;
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat scrollOffset = scrollView.contentOffset.y;
Works like a charm, I can read the scroll position, but when I'm trying to animate UIView, by linking the scrollView.contentOffset.y to the UIView "y" position;
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat scrollOffset = scrollView.contentOffset.y;
[UIView beginAnimations:#"UIViewAnimationCurveEaseInOut" context:nil];
bgView.center = CGPointMake(bgView.center.x, bgView.center.y+scrollOffset);
[UIView commitAnimations];
}
So I tried to make the UIView bigger to the original size of the image 640x832 to be able to navigate on it, but doesn't seems to work.
bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 640, 832)];
bgView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"homelights.png"]];
Any idea why this is happening?
Your table view is a subclass of UIScrollView and your delegate for the table view is also (automatically) a delegate of the scroll view. Implement the scrollViewDidScroll: delegate method and use it to monitor how the table view has changed and move your background view.

is groupTableViewBackgroundColor deprecated on iOS 6?

I was just testing my app with iOS 6.0 and Xcode 4.5GM and I have set up a view like this:
[self.view setBackgroundColor:[UIColor groupTableViewBackgroundColor]];
So, the view has the same pattern than a common table view.
This works fine on iOS 4 and 5, but in iOS 6 it just gives me a white background.
Is this deprecated? If so, how can I replace it?
Thanks
This method will be deprecated during the 6.0 seed program
If you want to have a background in your own view that looks like the table view background,
then you should create an empty table view and place it behind your content.
First, add this to your viewDidLoad:
self.tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"tableViewBackground.png"]];
OR
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"tableViewBackground.png"]];
Then add this images to your app:
tableViewBackground.png
tableViewBackground#2x.png
I've written a UIColor category to replace groupTableViewBackgroundColor:
#interface UIColor (UITableViewBackground)
+ (UIColor *)groupTableViewBackgroundColor;
#end
#implementation UIColor (UITableViewBackground)
+ (UIColor *)groupTableViewBackgroundColor
{
__strong static UIImage* tableViewBackgroundImage = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
UIGraphicsBeginImageContextWithOptions(CGSizeMake(7.f, 1.f), NO, 0.0);
CGContextRef c = UIGraphicsGetCurrentContext();
[[self colorWithRed:185/255.f green:192/255.f blue:202/255.f alpha:1.f] setFill];
CGContextFillRect(c, CGRectMake(0, 0, 4, 1));
[[self colorWithRed:185/255.f green:193/255.f blue:200/255.f alpha:1.f] setFill];
CGContextFillRect(c, CGRectMake(4, 0, 1, 1));
[[self colorWithRed:192/255.f green:200/255.f blue:207/255.f alpha:1.f] setFill];
CGContextFillRect(c, CGRectMake(5, 0, 2, 1));
tableViewBackgroundImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
});
return [self colorWithPatternImage:tableViewBackgroundImage];
}
#end
This solution also allows to tweak the appearance of the background. Feel free to change the drawing code :)
In iOS6 SKD, comments in UIInterface.h suggest the following:
Group style table view backgrounds can no longer be represented by
a simple color.
If you want to have a background in your own view
that looks like the table view background, then you should create
an empty table view and place it behind your content.
This method will be deprecated during the 6.0 seed program
A simple solution is to set the background with equivalent RGB values:
[self.view setBackgroundColor:[UIColor colorWithRed:215.0/255.0 green:217.0/255.0 blue:223.0/255.0 alpha:1.0]];
You can them set the view background to color to White or whatever you like in the xib to suppress the warning.
If it helps anyone, here's specifically what I'm doing in my custom view to get this background (using hint from Mr Beloeuvre)
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor clearColor];
UITableView *tv = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
[self.view addSubview:tv];
[self.view sendSubviewToBack:tv];
// ...
}
Try this:
[myTableView setBackgroundView:nil];
[myTableView setBackgroundView:[[[UIView alloc] init] autorelease]];
You may have difficult time to locate the view if you use storyboard and have many views. You can click on "Show the Version editor" button the right top corner. This will change story view to XML text view. Search for "groupTableViewBackGroundColor". You should find views with this attribute.
It's good idea to use standard methods for previous iOs versions. So I improved solution of James Boutcher:
+ (void)setBackgroundColorForTableView:(UITableView*) tableView
{
UIColor* color = [UIColor whiteColor];
NSString* version = [[UIDevice currentDevice] systemVersion];
if([version floatValue] < 6.0)
{
tableView.backgroundColor = color;
}
else
{
tableView.backgroundView = nil;
UIView* bv = [[UIView alloc] init];
bv.backgroundColor = color;
tableView.backgroundView = bv;
[bv release];
}
}
Elaborating on #NSElvis's solution, here is the identical grouped table view background asset (it's wide enough so you don't get funny effects in landscape orientation)
back-tableview#2x.png
To use it, simply do
[YOUR_VIEW setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"back-tableview"]]];

How to customize the callout bubble for MKAnnotationView?

I'm currently working with the mapkit and am stuck.
I have a custom annotation view I am using, and I want to use the image property to display the point on the map with my own icon. I have this working fine. But what I would also like to do is to override the default callout view (the bubble that shows up with the title/subtitle when the annotation icon is touched). I want to be able to control the callout itself: the mapkit only provides access to the left and right ancillary callout views, but no way to provide a custom view for the callout bubble, or to give it zero size, or anything else.
My idea was to override selectAnnotation/deselectAnnotation in my MKMapViewDelegate, and then draw my own custom view by making a call to my custom annotation view. This works, but only when canShowCallout is set to YES in my custom annotation view class. These methods are NOT called if I have this set to NO (which is what I want, so that the default callout bubble is not drawn). So I have no way of knowing if the user touched on my point on the map (selected it) or touched a point that is not part of my annotation views (delected it) without having the default callout bubble view show up.
I tried going down a different path and just handling all touch events myself in the map, and I can't seem to get this working. I read other posts related to catching touch events in the map view, but they aren't exactly what I want. Is there a way to dig into the map view to remove the callout bubble before drawing? I'm at a loss.
Any suggestions? Am I missing something obvious?
There is an even easier solution.
Create a custom UIView (for your callout).
Then create a subclass of MKAnnotationView and override setSelected as follows:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
if(selected)
{
//Add your custom view to self...
}
else
{
//Remove your custom view...
}
}
Boom, job done.
detailCalloutAccessoryView
In the olden days this was a pain, but Apple has solved it, just check the docs on MKAnnotationView
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.detailCalloutAccessoryView = UIImageView(image: UIImage(named: "zebra"))
Really, that's it. Takes any UIView.
Continuing on from #TappCandy's brilliantly simple answer, if you want to animate your bubble in the same way as the default one, I've produced this animation method:
- (void)animateIn
{
float myBubbleWidth = 247;
float myBubbleHeight = 59;
calloutView.frame = CGRectMake(-myBubbleWidth*0.005+8, -myBubbleHeight*0.01-2, myBubbleWidth*0.01, myBubbleHeight*0.01);
[self addSubview:calloutView];
[UIView animateWithDuration:0.12 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^(void) {
calloutView.frame = CGRectMake(-myBubbleWidth*0.55+8, -myBubbleHeight*1.1-2, myBubbleWidth*1.1, myBubbleHeight*1.1);
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.1 animations:^(void) {
calloutView.frame = CGRectMake(-myBubbleWidth*0.475+8, -myBubbleHeight*0.95-2, myBubbleWidth*0.95, myBubbleHeight*0.95);
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.075 animations:^(void) {
calloutView.frame = CGRectMake(-round(myBubbleWidth/2-8), -myBubbleHeight-2, myBubbleWidth, myBubbleHeight);
}];
}];
}];
}
It looks fairly complicated, but as long as the point of your callout bubble is designed to be centre-bottom, you should just be able to replace myBubbleWidth and myBubbleHeight with your own size for it to work. And remember to make sure your subviews have their autoResizeMask property set to 63 (i.e. "all") so that they scale correctly in the animation.
:-Joe
Found this to be the best solution for me.
You'll have to use some creativity to do your own customizations
In your MKAnnotationView subclass, you can use
- (void)didAddSubview:(UIView *)subview{
int image = 0;
int labelcount = 0;
if ([[[subview class] description] isEqualToString:#"UICalloutView"]) {
for (UIView *subsubView in subview.subviews) {
if ([subsubView class] == [UIImageView class]) {
UIImageView *imageView = ((UIImageView *)subsubView);
switch (image) {
case 0:
[imageView setImage:[UIImage imageNamed:#"map_left"]];
break;
case 1:
[imageView setImage:[UIImage imageNamed:#"map_right"]];
break;
case 3:
[imageView setImage:[UIImage imageNamed:#"map_arrow"]];
break;
default:
[imageView setImage:[UIImage imageNamed:#"map_mid"]];
break;
}
image++;
}else if ([subsubView class] == [UILabel class]) {
UILabel *labelView = ((UILabel *)subsubView);
switch (labelcount) {
case 0:
labelView.textColor = [UIColor blackColor];
break;
case 1:
labelView.textColor = [UIColor lightGrayColor];
break;
default:
break;
}
labelView.shadowOffset = CGSizeMake(0, 0);
[labelView sizeToFit];
labelcount++;
}
}
}
}
And if the subview is a UICalloutView, then you can screw around with it, and what's inside it.
I had the same problem. There is a serious of blog posts about this topic on this blog http://spitzkoff.com/craig/?p=81.
Just using the MKMapViewDelegate doesn't help you here and subclassing MKMapView and trying to extend the existing functionality also didn't work for me.
What I ended up doing is to create my own CustomCalloutView that I am having on top of my MKMapView. You can style this view in any way you want.
My CustomCalloutView has a method similar to this one:
- (void) openForAnnotation: (id)anAnnotation
{
self.annotation = anAnnotation;
// remove from view
[self removeFromSuperview];
titleLabel.text = self.annotation.title;
[self updateSubviews];
[self updateSpeechBubble];
[self.mapView addSubview: self];
}
It takes an MKAnnotation object and sets its own title, afterward it calls two other methods which are quite ugly which adjust the width and size of the callout contents and afterward draw the speech bubble around it at the correct position.
Finally the view is added as a subview to the mapView. The problem with this solution is that it is hard to keep the callout at the correct position when the map view is scrolled. I am just hiding the callout in the map views delegate method on a region change to solve this problem.
It took some time to solve all those problems, but now the callout almost behaves like the official one, but I have it in my own style.
Basically to solve this, one needs to:
a) Prevent the default callout bubble from coming up.
b) Figure out which annotation was clicked.
I was able to achieve these by:
a) setting canShowCallout to NO
b) subclassing, MKPinAnnotationView and overriding the touchesBegan and touchesEnd methods.
Note: You need to handle the touch events for the MKAnnotationView and not MKMapView
I just come up with an approach, the idea here is
// Detect the touch point of the AnnotationView ( i mean the red or green pin )
// Based on that draw a UIView and add it to subview.
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
{
CGPoint newPoint = [self.mapView convertCoordinate:selectedCoordinate toPointToView:self.view];
// NSLog(#"regionWillChangeAnimated newPoint %f,%f",newPoint.x,newPoint.y);
[testview setCenter:CGPointMake(newPoint.x+5,newPoint.y-((testview.frame.size.height/2)+35))];
[testview setHidden:YES];
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
CGPoint newPoint = [self.mapView convertCoordinate:selectedCoordinate toPointToView:self.view];
// NSLog(#"regionDidChangeAnimated newPoint %f,%f",newPoint.x,newPoint.y);
[testview setCenter:CGPointMake(newPoint.x,newPoint.y-((testview.frame.size.height/2)+35))];
[testview setHidden:NO];
}
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
NSLog(#"Select");
showCallout = YES;
CGPoint point = [self.mapView convertPoint:view.frame.origin fromView:view.superview];
[testview setHidden:NO];
[testview setCenter:CGPointMake(point.x+5,point.y-(testview.frame.size.height/2))];
selectedCoordinate = view.annotation.coordinate;
[self animateIn];
}
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
NSLog(#"deSelect");
if(!showCallout)
{
[testview setHidden:YES];
}
}
Here - testview is a UIView of size 320x100 - showCallout is BOOL - [self animateIn]; is the function that does view animation like UIAlertView.
You can use leftCalloutView, setting annotation.text to #" "
Please find below the example code:
pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if(pinView == nil){
pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease];
}
CGSize sizeText = [annotation.title sizeWithFont:[UIFont fontWithName:#"HelveticaNeue" size:12] constrainedToSize:CGSizeMake(150, CGRectGetHeight(pinView.frame)) lineBreakMode:UILineBreakModeTailTruncation];
pinView.canShowCallout = YES;
UILabel *lblTitolo = [[UILabel alloc] initWithFrame:CGRectMake(2,2,150,sizeText.height)];
lblTitolo.text = [NSString stringWithString:ann.title];
lblTitolo.font = [UIFont fontWithName:#"HelveticaNeue" size:12];
lblTitolo.lineBreakMode = UILineBreakModeTailTruncation;
lblTitolo.numberOfLines = 0;
pinView.leftCalloutAccessoryView = lblTitolo;
[lblTitolo release];
annotation.title = #" ";
I've pushed out my fork of the excellent SMCalloutView that solves the issue with providing a custom view for callouts and allowing flexible widths/heights pretty painlessly. Still some quirks to work out, but it's pretty functional so far:
https://github.com/u10int/calloutview

Resources