I'm working with a Google Maps View and I want to add a button to the map that when tapped, will move the camera to a specific location. I currently have a button outlet and an action connected to the button.
#IBAction func locationTapped(_ sender: Any) {
print("tapped")
let location = GMSCameraPosition.camera(withLatitude: place.latitude, longitude: place.longitude, zoom: 17.0)
mapView.camera = location
}
place exists but for some reason, the camera will not budge. I've tried different versions of code and looked at the Google Maps documentation but none of the options are producing results. Can anyone tell me what I'm doing wrong?
The GMSMapView class has the following function:
animate(to: GMSCameraPosition)
So in your code sample, instead of doing this:
mapView.camera = location
Try doing this:
mapView.animate(to: location)
Hope this helps!
in Swift3 and Swift4
for moving marker to current position use this:
func myLocationBtnAction(_ sender: UIButton) {
mapView.moveCamera(GMSCameraUpdate.setTarget(CLLocationCoordinate2D(latitude: (mapView.myLocation?.coordinate.latitude)!, longitude: (mapView.myLocation?.coordinate.longitude)!), zoom: 16))
and for a specific location use this:
let camera = GMSCameraPosition.camera(withLatitude: lat, longitude: lng, zoom: 16)
mapView?.camera = camera
mapView?.animate(to: camera)
and don't forget to extend GMSAutocompleteViewControllerDelegate for current location
Swift 2.3
This code is used for my purpose. In which marker tap event used, which moves camera position of map. Hope you find your solution.
func mapView(mapView: GMSMapView, didTapMarker marker: GMSMarker) -> Bool {
mapView.selectedMarker = marker
var point = mapView.projection.pointForCoordinate(marker.position)
let camera = mapView.projection.coordinateForPoint(point)
let position = GMSCameraUpdate.setTarget(camera)
mapView.animateWithCameraUpdate(position)
return true
}
For Objective-c the method is:
[mapView moveCamera:[GMSCameraUpdate setTarget:<CLLocationCoordinate2DMake>]];
Maybe this is to late but i resolve that problem with adding this:
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500), execute: {
let camera = GMSCameraPosition.camera(withLatitude: lat!, longitude: lon!, zoom: 17.0)
self.mMap.animate(to: camera)
})
You have to wait until map load delegate
func moveMapCamera(at cordinate: CLLocationCoordinate2D, animated: Bool = false) {
let camera = MKMapCamera()
camera.centerCoordinate = cordinate
camera.pitch = 0
camera.altitude = 9000
mapV.setCamera(camera, animated: animated)
}
Related
Currently my app opens a custom infowindow when the MapView delegate calls the didTap protocol. This then calls a function which initializes the needed aspects of the infowindow shown below ...
var tappedOverlay : GMSOverlay?
var customInfoWindow : CustomInfoWindow?
var mapView: GMSMapView!
override func viewDidLoad(){
super.viewDidLoad()
self.customInfoWindow = CustomInfoWindow().loadView()
let camera = GMSCameraPosition.camera(withLatitude: 37, longitude: -77, zoom: 16.0)
mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
mapView.delegate = self
self.view = mapView
//this is where i attempt to force a infoWindow to open
tappedOverlay = overlay
initInfoWindow(overlay: overlay)
}
fun initInfoWindow(overlay: GMSOverlay){
mapView.animate(toLocation: position!)
let point = mapView.projection.point(for: position!)
let newPoint = mapView.projection.coordinate(for: point)
let camera = GMSCameraUpdate.setTarget(newPoint)
mapView.animate(with: camera)
let background = UIColor.infoWindowBackground
customInfoWindow?.layer.backgroundColor = background.cgColor
customInfoWindow?.layer.cornerRadius = 8
customInfoWindow?.center = mapView.projection.point(for: position!)
customInfoWindow?.center.y -= 100
customInfoWindow?.CustomWindowLabel.text = overlay.title
customInfoWindow?.CustomWindowSubLabel.lineBreakMode = .byWordWrapping
customInfoWindow?.CustomWindowSubLabel.numberOfLines = 0
mapView.addSubview(customInfoWindow!)
}
func mapView(_ mapView: GMSMapView, didTap Overlay: GMSOverlay){
initInfoWindow(overlay: overlay)
}
Now I would like to have the app automatically open a certain infowindow as soon as it loads.
When I try to manually display the infoWindow on load by calling the function in viewDidLoad(), I have to comment out the mapView.animate(with: camera) line otherwise the map tiles will never load. Someone pointed out to me that the mapView methods have some 'background' information about the overlay when they are called, so I added the tappedOverlay = overlay line, this gets close in that part of the infoWindow is displayed when the app is loaded. However, this and all other 'regular' infoWindows appear without a background and not centered on the point and cannot be interacted with.
The infoWindow's are a subclass of UIView loaded from a XIB file.
The above code is what I thought would be relevant extracted from a larger code base. Let me know if anything needs to be added!
Any help is appreciated!
Maybe this answer will help someone else. The issue was in the mapView.projection functions, they were returning essentially default values. I'm not entirely sure, but it seems when you click on a marker the mapView changes part of the frame = ( 0 0;) variable in the background, so this lead me to change the mapView initialization.
So instead of ...
let camera = GMSCameraPosition.camera(withLatitude: 37, longitude: -77, zoom: 16.0)
mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
We need ...
let camera = GMSCameraPosition.camera(withLatitude: LAT_OF_YOUR_INFOWINDOW,
longitude: LONG_OF_YOUR_INFOWINDOW,
zoom: 16.0)
mapView = GMSMapView.map(withFrame: self.view.bounds, camera: camera)
I have tried to zoom in and zoom out the GMSCamera but failed to perform this with animation. I can have gone through the documentation as well. but nothing helped.
UIView.animate(withDuration: 5.0) {
let zoom = GMSCameraUpdate.zoom(to: 15.0)
self.mapView.animate(toZoom: zoom)
}
The above code does not animate the mapview.
Try the below code. You may update it for latest swift syntax.
mapView.camera = GMSCameraPosition.cameraWithLatitude(58.998400,longitude: 10.035604, zoom: 1)
CATransaction.begin()
CATransaction.setValue(2.0, forKey: kCATransactionAnimationDuration)
let city = GMSCameraPosition.cameraWithLatitude(58.998400,longitude: 10.035604, zoom: 15)
self.mapView.animateToCameraPosition(city)
CATransaction.commit()
You do not need to use UIView.animate on google map as google map has its own method to animate with zoom level.
You just need to call this method.
let lat = 21.78841 //latitude of the location to display on map
let lng = 72.25478 //longitude of the location to display on map
let camera = GMSCameraPosition(target: CLLocationCoordinate2D(latitude: lat, longitude: lng), zoom: 17)
mapView.animate(to: camera)
From Google's Doc.
/** Animates the camera of this map to |cameraPosition|. */
- (void)animateToCameraPosition:(GMSCameraPosition *)cameraPosition;
i Have a car icon in google map and which have to be moved in regular time interval. the location coordinates will be fetched from server and i have managed to change the location of marker by doing the code below but didint got a smooth movement
let camera = GMSCameraPosition.camera(withLatitude: (((self.driverArrival.value(forKey: "latitude")) as AnyObject).doubleValue)!,
longitude: (((self.driverArrival.value(forKey: "longitude")) as AnyObject).doubleValue)!, zoom: 15)
let position = CLLocationCoordinate2DMake((((self.driverArrival.value(forKey: "latitude")) as AnyObject).doubleValue)!, (((self.driverArrival.value(forKey: "longitude")) as AnyObject).doubleValue)!)
driverMarker.position = position
driverMarker.map = self.mapView
here driverdetails contains all the required data. Just want to know i can use any animation functions to achieve this?
You can use animate(to: GMSCameraPosition) to update map position with animation an example will look like this :-
func updateMapLocation(lattitude:CLLocationDegrees,longitude:CLLocationDegrees){
let camera = GMSCameraPosition.camera(withLatitude: lattitude, longitude: longitude, zoom: 16)
mapView?.camera = camera
mapView?.animate(to: camera)
}
and call the method like this
updateMapLocation(lattitude:-33.8683,longitude:151.2086)
For more information
Edit
For marker position update you can use a single marker and update its position with this code
CATransaction.begin()
CATransaction.setAnimationDuration(2.0)
marker.position = coordindates // CLLocationCoordinate2D coordinate
CATransaction.commit()
Please Don't use GMSCameraPosition for move pin in the map
You can use mapView.animate(toLocation: YOUR_COORDINATES) method to smoothly move pin in the map
self.mapView.animate(toLocation: CLLocationCoordinate2D(latitude: YOUR_LATITUDE, longitude: YOUR_LONGITUDE))
self.marker.position = coordinate
self.marker.map = self.mapView
Hope this helps!
Try this ...
Add GMSMapViewDelegate to your class,
self.mapView.delegate = self //Call delegate
//MARK - MapView delegates
func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) {
self.marker.map = mapView;
self.marker.position = position.target //Your target position
self.mapView.selectedMarker = self.marker //Your marker
DispatchQueue.main.async {
self.marker.snippet = "Getting address... " //Your snippet title
}
}
func mapView(_ mapView:GMSMapView, idleAt position:GMSCameraPosition) {
//Get address with village names and street names
self.getAddressForLatLng(latitude: "\(position.target.latitude)", longitude: "\(position.target.longitude)", zoomLevel: position.zoom)
}
I'm using google maps. Im getting user current location with course(angle) from cllocationmanger. After getting the location I'm adding to the GMSMapview.
Now my problem is car movement and map rotation. I want my map view to behave like googlemaps navigation. What I'm doing is after getting course of location I'm assigning it bearing of GMSMapview and not rorating the car.
But in navigation app they are rotating navigation arrow and also the map changing to north direction when ever there is a turn(left or right).
To achieve that do I need use both course and heading of CLLocationmanager.
here is my code. when ever there is a chnage in location im calling this method.
func ShowcurrentMarker()
{
currentlocationCoordinate = CLLocationCoordinate2DMake(LatestLocation.coordinate.latitude, LatestLocation.coordinate.longitude)
if(CurrentLocationMarker == nil)
{
CurrentLocationMarker = GMSMarker(position:currentlocationCoordinate)
CurrentLocationMarker.map = self.mapView
CurrentLocationMarker.icon = UIImage.init(named:"car_icon")
self.mapView.camera = GMSCameraPosition.camera(withLatitude: LatestLocation.coordinate.latitude, longitude: LatestLocation.coordinate.longitude, zoom: 18, bearing: CLLocationDirection.abs(LatestLocation.course), viewingAngle: 65)
}
else
{
CATransaction.begin()
CATransaction.setAnimationDuration(2)
CurrentLocationMarker.position = currentlocationCoordinate
self.mapView.camera = GMSCameraPosition.camera(withLatitude: LatestLocation.coordinate.latitude, longitude: LatestLocation.coordinate.longitude, zoom: 18, bearing: CLLocationDirection.abs(LatestLocation.course), viewingAngle: 65)
CATransaction.commit()
}
}
Please help me..
Thank you...
I am having issues with the order/way that I'm setting up my UIMapView. This is what I would like to happen:
View appears - Map rotates to specified heading
Reset button tapped - If user has moved the map, it will reset to the default heading and zoom
At the moment the map is rotated to the heading when the map appears, but the reset button does nothing. I suspect this is down to the order I am doing things because if I flip two lines of code around, it works, but it doesn't rotate to the correct heading when the map appears.
Here is my code:
#IBAction func rotateToDefault(sender: AnyObject) {
mapView.setRegion(zoomRegion, animated: true)
mapView.camera.heading = parkPassed.orientation!
}
override func viewWillAppear(animated: Bool) {
setUpMapView()
}
override func viewDidAppear(animated: Bool) {
mapView.setRegion(zoomRegion, animated: true)
mapView.camera.heading = parkPassed.orientation!
}
func setUpMapView() {
rideArray = ((DataManager.sharedInstance.rideArray) as NSArray) as! [Ride]
zoomRegion = MKCoordinateRegionMakeWithDistance(CLLocationCoordinate2D(latitude: parkPassed.latitude!, longitude: parkPassed.longitude!), 1000, 1000)
mapView.setRegion(zoomRegion, animated: true)
mapView.delegate = self
for ride in rideArray {
var subtitle = ""
if locationManager.location == nil {
subtitle = "Distance unavailable"
} else {
let userLocation = CLLocation(latitude: locationManager.location.coordinate.latitude, longitude: locationManager.location.coordinate.longitude)
let annotationLocation = CLLocation(latitude: ride.latitude!, longitude: ride.longitude!)
var distance = Int(CLLocationDistance(annotationLocation.distanceFromLocation(userLocation)))
if distance > 1000 {
distance = distance / 1000
subtitle = "\(distance) kilometers"
} else {
subtitle = "\(distance) meters"
}
}
let annotation = RideAnnotation(coordinate: CLLocationCoordinate2DMake(ride.latitude!, ride.longitude!), title: ride.name!, subtitle: subtitle)
self.qTree.insertObject(annotation)
annotationsAdded.insertObject(annotation, atIndex: 0)
println(qTree.count)
}
}
Anyone have any suggestions?
I had a similar problem.
It appears region and camera are two mutual exclusive concepts to determine how you see which part of the map.
If you use region, you have coordinate and span to determine what you see (you already did this in your code)
If you use camera, you have coordinate, distance, pitch and heading to determine how you see the map.
use mapView.setCamera(...) to smoothly change what you see, including the heading.
To define your camera view you do something like
let camera = MKMapCamera(lookingAtCenterCoordinate: userLocation, fromDistance: 1000, pitch: 0, heading: heading)
self.mapView.setCamera(camera, animated: false)
From Apples Documentation:
Assigning a new camera to this property updates the map immediately and without animating the change. If you want to animate changes in camera position, use the setCamera:animated: method instead.