I created an iOS application based on maps in which I thought to use Google Maps SDK for iOS instead of Mapkit, I found the documentation but it I didn’t find methods related to custom annotation view, Can anyone provide me the solution for how to create custom annotation view(info window) and how to add content(title, snippet) for it.
I don't know about y'all, but I find Google's rendered UIView info windows to be a bit restricting. Using SMCalloutView and Ryan Maxwell's example project, it's possible to present more interactive views.
This works on Google Maps SDK v1.8.1, as of 2014-June-10.
First, do some set up:
#import <SMCalloutView/SMCalloutView.h>
static const CGFloat CalloutYOffset = 10.0f;
#interface ViewController ()
#property (strong, nonatomic) SMCalloutView *calloutView;
#property (strong, nonatomic) UIView *emptyCalloutView;
#end
Initialize SMCalloutView, add a button to it, then create an empty UIView:
- (void)viewDidLoad
{
/* all your other view init, settings, etc... */
self.calloutView = [[SMCalloutView alloc] init];
self.calloutView.hidden = YES;
UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[button addTarget:self
action:#selector(calloutAccessoryButtonTapped:)
forControlEvents:UIControlEventTouchUpInside];
self.calloutView.rightAccessoryView = button;
self.emptyCalloutView = [[UIView alloc] initWithFrame:CGRectZero];
}
We have to draw that empty UIView to satisfy the Maps SDK, but the view we will display is SMCalloutView. I also set a reuseable vertical offset for the callout view.
Add delegate methods to handle info window calls:
#pragma mark - GMSMapViewDelegate
- (UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(GMSMarker *)marker {
CLLocationCoordinate2D anchor = marker.position;
CGPoint point = [mapView.projection pointForCoordinate:anchor];
self.calloutView.title = marker.title;
self.calloutView.calloutOffset = CGPointMake(0, -CalloutYOffset);
self.calloutView.hidden = NO;
CGRect calloutRect = CGRectZero;
calloutRect.origin = point;
calloutRect.size = CGSizeZero;
[self.calloutView presentCalloutFromRect:calloutRect
inView:mapView
constrainedToView:mapView
animated:YES];
return self.emptyCalloutView;
}
- (void)mapView:(GMSMapView *)pMapView didChangeCameraPosition:(GMSCameraPosition *)position {
/* move callout with map drag */
if (pMapView.selectedMarker != nil && !self.calloutView.hidden) {
CLLocationCoordinate2D anchor = [pMapView.selectedMarker position];
CGPoint arrowPt = self.calloutView.backgroundView.arrowPoint;
CGPoint pt = [pMapView.projection pointForCoordinate:anchor];
pt.x -= arrowPt.x;
pt.y -= arrowPt.y + CalloutYOffset;
self.calloutView.frame = (CGRect) {.origin = pt, .size = self.calloutView.frame.size };
} else {
self.calloutView.hidden = YES;
}
}
- (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate {
self.calloutView.hidden = YES;
}
- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker {
/* don't move map camera to center marker on tap */
mapView.selectedMarker = marker;
return YES;
}
Handle touches on the callout button, here using an alert view with marker title and snippet:
- (void)calloutAccessoryButtonTapped:(id)sender {
if (mapView_.selectedMarker) {
GMSMarker *marker = mapView_.selectedMarker;
//NSDictionary *userData = marker.userData;
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:marker.title
message:marker.snippet
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
}
}
Obviously, make sure your ViewController(.h) listens to GMSMapViewDelegate:
#interface ViewController : UIViewController <GMSMapViewDelegate>
And that should basically work. For a complete xcode project, see the aforementioned example from Ryan Maxwell.
If you check GMSMapView.h within GoogleMaps.Framework, you can see the below method which should let you add a custom infowindow for a marker, instead of using standard title and snippet alone:
NOTE you (op) say annotationView=infoWindow
BUT NORMAL: annotationView = marker itself and calloutView = infoWindow
/**
* Called when a marker is about to become selected, and provides an optional
* custom info window to use for that marker if this method returns a UIView.
* If you change this view after this method is called, those changes will not
* necessarily be reflected in the rendered version.
*
* The returned UIView must not have bounds greater than 500 points on either
* dimension. As there is only one info window shown at any time, the returned
* view may be reused between other info windows.
*
* #return The custom info window for the specified marker, or nil for default
*/
- (UIView *)mapView:(GMSMapView *)mapView
markerInfoWindow:(id<GMSMarker>)marker;
Related
I'm testing googlemaps using xamarin. Android platforms is ok, but in iOS i cannot see map background. I declared a variable with my credencial in AppDelegate.cs
The test only show pin address. The problem is exclusively with the background (street or satellite)
Test on Android OK.
This object receives all information about the location
readonly Pin _pinCBC = new Pin()
{
Icon = BitmapDescriptorFactory.DefaultMarker(Color.Red),
Type = PinType.Place,
Label = "61CBC",
Address = "Washington Avenue",
Position = new Position(-3.777777, -38.488888),
ZIndex = 1
};
And this method prints the map on screen. Initialize componente and after add object and positioning the pin to center
public MapsPage()
{
InitializeComponent();
map.MyLocationEnabled = true;
map.UiSettings.MyLocationButtonEnabled = true;
_pinCBC.IsDraggable = true;
map.Pins.Add(_pinCBC);
map.SelectedPin = _pinCBC;
map.MoveToRegion(MapSpan.FromCenterAndRadius(_pinCBC.Position, Distance.FromMeters(5000)), true);
}
How could I show background map. Maybe there is any missing property to inform?
iOS Simulator
Problem:
My app crashes, everytime I press the "< chat" button (this only happens when I add the purple SKEmitterNode to GameScene.m).
Error:
Code:
1) From UIViewController present DrawDrawViewController (UIViewController):
DrawDrawViewController *drawDrawViewController = [[DrawDrawViewController alloc] init];
[self.navigationController pushViewController:drawDrawViewController animated:YES];
2) Inside DrawDrawViewController (UIViewController) Display the GameScene (SKScene)
#interface DrawDrawViewController()
#property (nonatomic) SKView *drawDrawView;
#property (nonatomic) GameScene *scene;
#end
- (void)viewDidLoad {
[super viewDidLoad];
// Configure the view.
_drawDrawView = [[SKView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
[self.view addSubview:_drawDrawView];
if(!_drawDrawView.scene) {
_drawDrawView.ignoresSiblingOrder = YES;
// Create and configure the scene.
_scene = [GameScene unarchiveFromFile:#"GameScene"];
_scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[_drawDrawView presentScene:_scene];
}
}
3) Inside GameScene.m display "hello world" and also a SKEmitterNode:
-(void)didMoveToView:(SKView *)view {
/* Setup your scene here */
SKLabelNode *myLabel = [SKLabelNode labelNodeWithFontNamed:#"Chalkduster"];
myLabel.text = #"Hello, World!";
myLabel.fontSize = 65;
myLabel.position = CGPointMake(CGRectGetMidX(self.frame),
CGRectGetMidY(self.frame));
[self addChild:myLabel];
NSString *fireEmmitterPath = [[NSBundle mainBundle] pathForResource:#"magic" ofType:#"sks"];
SKEmitterNode *fireEmmitter = [NSKeyedUnarchiver unarchiveObjectWithFile:fireEmmitterPath];
fireEmmitter = [NSKeyedUnarchiver unarchiveObjectWithFile:fireEmmitterPath];
fireEmmitter.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2 - 200);
fireEmmitter.name = #"fireEmmitter";
fireEmmitter.zPosition = 1;
fireEmmitter.targetNode = self;
fireEmmitter.particleBirthRate = 100;
[self addChild: fireEmmitter];
}
I'm trying to place an image in a GMSGroundOverlay but noticed something weird when I zoom out to zoom < 3.0 (world level).
The image should cover the whole screen of the iPad which is does fine at zoom >= 3.0. but if I zoom out the image is placed offscreen and is visible if you pan left or right.
It's like its been wrapped around the globe but on the reverse side.
The user pans/zooms the map.
When they stop I get the screen
dimensions for the ipad I call a web service to get the image to
place over the whole screen.
It contains ship positions and alpha channel so you can see the map.
I find the 4 points of the map thats on the iPad.
//southWest = nearLeft
CLLocationCoordinate2D SW_ = CLLocationCoordinate2DMake([vesselTileRequest_.nearLeft_latitude doubleValue],
[vesselTileRequest_.nearLeft_longitude doubleValue]);
//northEast = farRight = top right of ipad screen
CLLocationCoordinate2D NE_ = CLLocationCoordinate2DMake([vesselTileRequest_.farRight_latitude doubleValue],
[vesselTileRequest_.farRight_longitude doubleValue]);
//-----------------------------------------------------------------------------------
CLLocationCoordinate2D SE_ = CLLocationCoordinate2DMake([vesselTileRequest_.nearRight_latitude doubleValue],
[vesselTileRequest_.nearRight_longitude doubleValue]);
//northEast = farRight = top right of ipad screen
CLLocationCoordinate2D NW_ = CLLocationCoordinate2DMake([vesselTileRequest_.farLeft_latitude doubleValue],
[vesselTileRequest_.farLeft_longitude doubleValue]);
I place the image at SW,NE as per google docs:
overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SW_
coordinate:NE_];
self.overlay = [GMSGroundOverlay groundOverlayWithBounds:overlayBounds
icon:responseImage_];
This works fine for any zoom level higher than 3.0.
But when we zoom out, nothing appears on the map but if you pan left or right the image has bee mapped to the opposite side of the earth.
I've had to turn of overlap mapping when zoom is < 3.0.
I tried every combination of NW/NE/SW/SE combo but all opposite corners just put the image on the wrong side of the earth.
if(self.mapView.camera.zoom < 3.0){
//nothing appears
// overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:NW_
// coordinate:NE_];
// overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:NW_
// coordinate:SW_];
//
//appears but off screen
// overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:NW_
// coordinate:SE_];
// //nothing
// overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:NE_
// coordinate:NW_];
//off screen
// overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:NE_
// coordinate:SW_];
// overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:NE_
// coordinate:SE_];
// overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SW_
// coordinate:NW_];
// overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SW_
// coordinate:NE_];
// overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SW_
// coordinate:SW_];
// overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SW_
// coordinate:SE_];
// overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SE_
// coordinate:NW_];
// overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SE_
// coordinate:NE_];
overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SE_
coordinate:SW_];
overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SE_
coordinate:SW_];
self.overlay = [GMSGroundOverlay groundOverlayWithBounds:overlayBounds
icon:responseImage_];
//-----------------------------------------------------------------------------------
//// CLLocationCoordinate2D position_farLeft = CLLocationCoordinate2DMake(self.mapView.projection.visibleRegion.farLeft.latitude,
//// self.mapView.projection.visibleRegion.farLeft.longitude);
// CLLocationCoordinate2D position_farLeft = CLLocationCoordinate2DMake(0.0,
// 0.0);
//
// DebugLog(#"self.mapView.camera.zoom:%f",self.mapView.camera.zoom);
// self.overlay = [GMSGroundOverlay groundOverlayWithPosition:position_farLeft
// icon:responseImage_
// zoomLevel:self.mapView.camera.zoom];
//-----------------------------------------------------------------------------------
}else{
//correct as of docs
overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SW_
coordinate:NE_];
self.overlay = [GMSGroundOverlay groundOverlayWithBounds:overlayBounds
icon:responseImage_];
}
I also tried other methods to create the overlay but if I hard code the position to 0,0 so on the equator. It appears over australia. Its again on the opposite side of the earth to where it should be
CLLocationCoordinate2D position_farLeft = CLLocationCoordinate2DMake(self.mapView.projection.visibleRegion.farLeft.latitude,
self.mapView.projection.visibleRegion.farLeft.longitude);
CLLocationCoordinate2D position_farLeft = CLLocationCoordinate2DMake(0.0,
0.0);
DebugLog(#"self.mapView.camera.zoom:%f",self.mapView.camera.zoom);
self.overlay = [GMSGroundOverlay groundOverlayWithPosition:position_farLeft
icon:responseImage_
zoomLevel:self.mapView.camera.zoom];
Result - nothing appears on the map
If i tap, hold and pan the image is off the screen.
if i do the same and pan to the right you see the image is exactly on the opposite side of the earth to the rect shown on the ipad screen
Digging into this, and for the first issue raised - the GMSGroundOverlay being on the reverse side of the globe at zoom levels of 3.0 or lower it appears that the culprit is that GMSCoordinateBounds initWithCoordinate:coordinate: initialization method normalizes the coordinates, as per the method documentation:
/**
* Inits the northEast and southWest bounds corresponding
* to the rectangular region defined by the two corners.
*
* It is ambiguous whether the longitude of the box
* extends from |coord1| to |coord2| or vice-versa;
* the box is constructed as the smaller of the two variants, eliminating the
* ambiguity.
*/
It turns out for an iPad, held in landscape mode, that zoom level 3.0 is the point at which a GMSGroundOverlay for the entire visibleRegion covers 180 degrees. Zoom out, and GMSCoordinateBounds normalizes to the smaller area, which just happens to be the other side of the globe.
The real answer here is to use GMSTileLayer.
I faced with the same problem. Try not to use GMSCoordinateBounds. Use groundOverlayWithPosition:
GMSGroundOverlay *overlay = [GMSGroundOverlay groundOverlayWithPosition:self.mapView.camera.target
icon:image
zoomLevel:self.mapView.camera.zoom];
overlay.bearing = 0;
overlay.map = self.mapView;
overlay.zIndex = 2;
I have been battling with google maps ios sdk for a couple hours, and I've a problema I haven't been able to solve. So here is what is happening:
I have a view controller in interface builder and with it .m and .h implmentation. The view controler has a view, and inside that view there is another view which is the on that holds the map, so in the identity inspector on the custom class it is set to GMSMapView.
This view has an outlet to the .h implementation and its is called mapView. And on the .m I have the following code:
(void)viewDidLoad
{
[super viewDidLoad];
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:10.49101
longitude:-66.902061
zoom:4];
self.mapView = [GMSMapView mapWithFrame:[self.mapView bounds] camera:camera];
self.mapView.myLocationEnabled = YES;
GMSMarkerOptions *options = [[GMSMarkerOptions alloc] init];
options.position = CLLocationCoordinate2DMake(-33.8683, 151.2086);
options.title = #"Sydney";
options.snippet = #"Australia";
[self.mapView addMarkerWithOptions:options];
}
As you can see I create the camera, then the map with the bounds of the view that is on interface builder (mapView). Now this is what is not working:
1) No matter what coordinates I enter the map always starts in England, I believe on (0,0) coordinates
2) My location doesn't appear
3)The marker doesn;t appear either.
4) IMPORTANT: the map is appearing but always over England.
I honestly don't know what is happening, I believe it has to do with the -(void)viewDidLoad
Because if I use the code that google provides writing the code on the loadView method it works, but the problem on doing it that way is that you can't access the views that I created on interface builder.
Thank you very much!
So I found an answer to the problem, without using a view in interface builder, all is donde programmatically. Here is the solution:
-(void)viewDidLoad{
[super viewDidLoad];
mapView = [[GMSMapView alloc] initWithFrame:CGRectZero];
[mapView setFrame:CGRectMake(0, 0, 400, 400)]; ////here you will have to specify the bounds of the view through CGRectMake
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:10.49101
longitude:-66.902061
zoom:4];
[mapView setCamera:camera];
mapView.myLocationEnabled = YES;
GMSMarkerOptions *options = [[GMSMarkerOptions alloc] init];
options.position = CLLocationCoordinate2DMake(-33.8683, 151.2086);
options.title = #"Sydney";
options.snippet = #"Australia";
[mapView addMarkerWithOptions:options];
[self.view addSubview:mapView];
[self.view sendSubviewToBack:mapView]; // just in case you need to send the map to the back, I do
}
I am trying to convert some Cocos2d-iphone code to Cocos2d-x code but some weird things happened with isometric tiled map.
The ground becomes totally dark.Please help me.
In Objective-C:
-(id) init { if ((self = [super init])) { CCTMXTiledMap* tileMap = [CCTMXTiledMap tiledMapWithTMXFile:#"isometric-with-border.tmx"];
[self addChild:tileMap z:-1 tag:TileMapNode];
CCTMXLayer* layer = [tileMap layerNamed:#"Collisions"]; layer.visible
= NO;
// Use a negative offset to set the tilemap's start position
tileMap.position = CGPointMake(-500, -500); …. } }
In C++:
bool TiledMap::init() { if ( !CCLayer::init() ) { return false; }
CCTMXTiledMap *tileMap =
CCTMXTiledMap::create("isometric-with-border.tmx");
this->addChild(tileMap,1,TileMapNode);
CCTMXLayer* layer = tileMap->layerNamed("Collisions");
layer->setVisible(false);
// Use a negative offset to set the tilemap's start position
tileMap->setPosition(-500, -500); …. }