Mapbox Swift compass visibilty property - swift

Hi all I am trying to get the compass to disappear off my map and have hit a brick wall. Below is my map initialization function and I'm not sure what the variable is. I have tried mapView.compassEnabled == false, mapView.compassView = nil and a few other things that I have found to no avail.
I appreciate any help!
#objc func initMap() {
if mapView != nil {
print("Attempting to init map that is already initialized, returning")
return
}
mapView = NavigationMapView(frame: UIApplication.shared.delegate!.window!!.bounds, // TODO: Set frame from react
styleURL: NSURL(string: "mapbox://styles/paway/ckcp7w04x03by1iqi1t26uilu") as URL?)
guard let mapView = self.mapView else { return }
mapView.zoomLevel = 2
mapView.delegate = self
mapView.locationManager.setDistanceFilter?(6)
PWLocationManager.shared.delegate = self
mapView.setCenter(CLLocationCoordinate2D(latitude: 37.0902, longitude: -95.7129), animated: false)
mapView.navigationMapViewDelegate = self
switch cameraMode {
case "overview":
mapCameraState = .overviewMode
mapView.userTrackingMode = .followWithHeading
case "followHeading":
mapCameraState = .followMode
mapView.userTrackingMode = .followWithHeading
default:
mapView.userTrackingMode = .none
}
mapView.isPitchEnabled = true
mapView.showsUserLocation = true
self.addSubview(mapView)
addMapTapRecognizer()
addObservers()
}

Updated answer**
This only works if you have a component that is on top of your map. IF you have just a plain map I would try using negative margins to push the compass out of view.
I found the answer here https://stackoverflow.com/a/57560116/13639051
I added :
mapView.compassViewPosition = .bottomLeft
mapView.compassViewMargins = CGPoint(x: 0, y: 0)
which hides the compass behind a bottom toast that is consistently across the project.

Related

Not able to add Multiple Markers in GSMapView xCode Swift 3

I am trying to add multiple Markers on Googlemaps in my app.
In the viewcontrolller under viewDidLoad I am able to load the map and a single marker.
override func viewDidLoad() {
super.viewDidLoad()
title = NSLocalizedString("section_map", comment: "test")
let camera = GMSCameraPosition.camera(withLatitude: 48.7784, longitude:9.18121, zoom: 12)
let mapView = GMSMapView.map(withFrame: .zero, camera: camera)
view = mapView
mapView.settings.myLocationButton = true
mapView.delegate = self
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: 48.7784,longitude: 9.18121)
marker.title = "title"
marker.snippet = "snipple"
marker.icon = UIImage(named:"pin_you")
marker.map = mapView
mapData()
}
It call mapData() and from there is json file is generated
after parsing setPin is called to set the markers
func setPin(){
DispatchQueue.main.async {
for item in self.mapItems {
print (" \(item.name) \(item.marker) \(item.latitude) \(item.longitude)")
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: item.latitude,longitude: item.longitude)
marker.title = item.name
marker.snippet = item.fulladdress
var iconImage: String
switch (item.marker){
case 1:
iconImage = "pin_silver"
case 2:
iconImage = "pin_blue"
case 3:
iconImage = "pin_gold"
case 6:
iconImage = "pin_you"
default:
iconImage = "pin_silver"
}
marker.icon = UIImage(named:iconImage)
marker.map = self.mapView
}
}
}
The pins are not shown.
The print in for item in self.mapItems shows
Position number A 1 48.76947562 9.15440351
Position number B 1 48.75716485 9.17081058
Position number C 1 48.81191625 9.22752149
Position number D 2 48.81192516 9.22766708
this means all the proper data is available.
However the map is there the one pin made in viewDidLoad
The Markers in function setPin are not shown or maybe not set.
Does any-one have an idea?
I have solved it in have changed the mapData(mapView: GMSMapView!) also for setPin(mapView: GMSMapView!)
func setpin(mapView: GMSMapView!){
DispatchQueue.main.async {
for item in self.mapItems {
print (" \(item.name) \(item.marker) \(item.latitude) \(item.longitude)")
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: item.latitude,longitude: item.longitude)
marker.title = item.name
marker.snippet = item.fulladdress
var iconImage: String
switch (item.marker){
case 1:
iconImage = "pin_silver"
case 2:
iconImage = "pin_blue"
case 3:
iconImage = "pin_gold"
case 6:
iconImage = "pin_you"
default:
iconImage = "pin_silver"
}
marker.icon = UIImage(named:iconImage)
marker.map = mapView
}
}
}
Clustering your markers, you can put a large number of markers on a map without making the map hard to read. The marker clustering utility helps you manage multiple markers at different zoom levels.
For the full code sample, see the ObjCDemoApp and SwiftDemoApp on GitHub.
To add a simple marker clusterer.
/// Point of Interest Item which implements the GMUClusterItem protocol.
class POIItem: NSObject, GMUClusterItem {
var position: CLLocationCoordinate2D
var name: String!
init(position: CLLocationCoordinate2D, name: String) {
self.position = position
self.name = name
}
}
The following code creates a cluster manager using the GMUNonHierarchicalDistanceBasedAlgorithm and the MUDefaultClusterRenderer that are included in the utility library:
class ViewController: UIViewController, GMUClusterManagerDelegate,
GMSMapViewDelegate {
private var mapView: GMSMapView!
private var clusterManager: GMUClusterManager!
override func viewDidLoad() {
super.viewDidLoad()
// Set up the cluster manager with the supplied icon generator and
// renderer.
let iconGenerator = GMUDefaultClusterIconGenerator()
let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
let renderer = GMUDefaultClusterRenderer(mapView: mapView,
clusterIconGenerator: iconGenerator)
clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm,
renderer: renderer)
// Generate and add random items to the cluster manager.
generateClusterItems()
// Call cluster() after items have been added to perform the clustering
// and rendering on map.
clusterManager.cluster()
}
}
Feed your markers into the cluster as GMUClusterItem objects by calling clusterManager:addItem:. The following code randomly generates cluster items (POIs) within the scope of the map's camera, then feeds them to the cluster manager:
/// Randomly generates cluster items within some extent of the camera and
/// adds them to the cluster manager.
private func generateClusterItems() {
let extent = 0.2
for index in 1...kClusterItemCount {
let lat = kCameraLatitude + extent * randomScale()
let lng = kCameraLongitude + extent * randomScale()
let name = "Item \(index)"
let item =
POIItem(position: CLLocationCoordinate2DMake(lat, lng), name: name)
clusterManager.addItem(item)
}
}
/// Returns a random value between -1.0 and 1.0.
private func randomScale() -> Double {
return Double(arc4random()) / Double(UINT32_MAX) * 2.0 - 1.0
}
Handle events on markers and clusters
class ViewController: UIViewController, GMUClusterManagerDelegate, GMSMapViewDelegate {
private var mapView: GMSMapView!
private var clusterManager: GMUClusterManager!
override func viewDidLoad() {
super.viewDidLoad()
// ... Rest of code omitted for easy reading.
// Register self to listen to both GMUClusterManagerDelegate and
// GMSMapViewDelegate events.
clusterManager.setDelegate(self, mapDelegate: self)
}
// MARK: - GMUClusterManagerDelegate
func clusterManager(clusterManager: GMUClusterManager, didTapCluster cluster: GMUCluster) {
let newCamera = GMSCameraPosition.cameraWithTarget(cluster.position,
zoom: mapView.camera.zoom + 1)
let update = GMSCameraUpdate.setCamera(newCamera)
mapView.moveCamera(update)
}
// MARK: - GMUMapViewDelegate
func mapView(mapView: GMSMapView, didTapMarker marker: GMSMarker) -> Bool {
if let poiItem = marker.userData as? POIItem {
NSLog("Did tap marker for cluster item \(poiItem.name)")
} else {
NSLog("Did tap a normal marker")
}
return false
}
}
For more Details please follow the Here

Set custom accessibilityIdentifier for GMSMarker

I use a Google Maps Api for maps and markers.
I enable accessibility for markers by setting: mapView.accessibilityElementsHidden = false
Now all my custom markers on map have accessibility ids like: myappname.GMSPlaceMarker_somenumbers, for example myappname.GMSPlaceMarker_0x600000170200.
How could i set a one accessibilityIdentifier for all pins, for example Map pin?
I already tried:
marker.accessibilityLabel = "Map pin" but it set label value, not id
marker.title = "Map pin" nothing changes
marker.setValue("Map pin", forKey: "accessibilityIdentifier") nothing changes
My marker is let marker = GMSPlaceMarker() where class GMSPlaceMarker: GMSMarker
try this,
func markPoints() {
var annotationCoord : CLLocationCoordinate2D = CLLocationCoordinate2D()
annotationCoord.latitude = (selectedLocation.latitude as NSString).doubleValue
annotationCoord.longitude = (selectedLocation.longitude as NSString).doubleValue
let annotationPoint: MKPointAnnotation = MKPointAnnotation()
annotationPoint.coordinate = annotationCoord
annotationPoint.title = selectedLocation.name
annotationPoint.subtitle = "Anand: 7348858742"
theMap.addAnnotation(annotationPoint)
}
If you are using swift 4 try this one,
var destionationMarker: GMSMarker!
func setupDriverMarker(coordinate: CLLocationCoordinate2D) {
destionationMarker = GMSMarker(position: coordinate)
for pin: GMSMarker in self.DestinationMarkerArray {
if pin.userData as! String == "drivermarker" {
pin.map = nil
}
}
destionationMarker.title = "Your Title"
destionationMarker.appearAnimation = GMSMarkerAnimation.pop
let images = #imageLiteral(resourceName: "ic_map_marker")
destionationMarker.icon = images
destionationMarker.userData = "drivermarker"
destionationMarker.opacity = 1
destionationMarker.map = journeyMapView
}
Implementing like this
DriverLocation = CLLocationCoordinate2D(latitude: 21.2362546, longitude: 72.8751862)
setupDriverMarker(coordinate: DriverLocation)
I had a similar issue as well, there is no accessibilityIdentifier for GMSMarker. What I did, setting either an accessibilityIdentifier to icon or iconView such as:
marker.icon?.accessibilityIdentifier = "something" or
marker.iconView?.accessibilityIdentifier = "something"

Left to right animation not working after upgrade to Swift 3.0

So I just upgraded to Swift 3.0 from 2.3. Everything else about my project is fine except for this line of code and its error:
if let delegate: AnyObject = completionDelegate {
leftToRightTransition.delegate = delegate //ERROR MESSAGE
}
The error message says:
Cannot assign value of type 'AnyObject' to type CAAnimation
Below is the full related block of code. Essentially this code is the animation. Elsewhere in my project (which I'm positive is not related to the problem, but just for context) there's code that allows the user to swipe through an array of images. This block is the animation part of it (the 'swipe away' animation'):
extension UIView {
func rightToLeftAnimation(_ duration: TimeInterval = 0.5, completionDelegate: AnyObject? = nil) {
// Create a CATransition object
let rightToLeftTransition = CATransition()
// Set its callback delegate to the completionDelegate that was provided
if let delegate: AnyObject = completionDelegate {
rightToLeftTransition.delegate = delegate //ERROR MESSAGE ON THIS LINE
}
rightToLeftTransition.type = kCATransitionPush
rightToLeftTransition.subtype = kCATransitionFromLeft
rightToLeftTransition.duration = duration
rightToLeftTransition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
rightToLeftTransition.fillMode = kCAFillModeRemoved
// Add the animation to the View's layer
self.layer.add(rightToLeftTransition, forKey: "rightToLeftTransition")
}
This worked just fine in Swift 2.3 but now it doesn't work. It's little stuff like this that drives me nuts... Any help would be appreciated ;)
It's now a CAAnimationDelegate:
if let delegate = completionDelegate as? CAAnimationDelegate {
rightToLeftTransition.delegate = delegate
}
Or just:
func rightToLeftAnimation(_ duration: TimeInterval = 0.5, completionDelegate: CAAnimationDelegate? = nil) {
// Create a CATransition object
let rightToLeftTransition = CATransition()
// Set its callback delegate to the completionDelegate that was provided
rightToLeftTransition.delegate = completionDelegate
rightToLeftTransition.type = kCATransitionPush
rightToLeftTransition.subtype = kCATransitionFromLeft
rightToLeftTransition.duration = duration
rightToLeftTransition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
rightToLeftTransition.fillMode = kCAFillModeRemoved
// Add the animation to the View's layer
layer.add(rightToLeftTransition, forKey: "rightToLeftTransition")
}
Try this , Its working in my code:
let swipeRight:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(ViewController.swipedRight))
swipeRight.direction = .right
SLIDEVIEW.addGestureRecognizer(swipeRight)
let swipeLeft:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(ViewController.swipedLeft))
swipeLeft.direction = .left
SLIDEVIEW.addGestureRecognizer(swipeLeft)
func swipedRight()
{
print("swiped right")
updateFrames(towards: "right")
}
func swipedLeft()
{
print("swiped left")
updateFrames(towards: "left")
}

How to update a GMSMapView with GMSCameraUpdate

I call animateWithCameraUpdate on a GMSMapView expecting it to change the map view to show the new GMSCoordinateBounds but it has no effect.
My map loads in a UICollectionViewReusableView to initially display Western Europe:
#IBOutlet weak var mapView: GMSMapView!
var fetchedResultsController : NSFetchedResultsController!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
let camera = GMSCameraPosition.cameraWithLatitude(51.48, longitude: 0, zoom: 4)
mapView.camera = camera
}
I then call a function to query all my locations and update the GMSMapView to show all my locations:
func plotAll(){
let bounds = GMSCoordinateBounds.init()
for property in fetchedResultsController.fetchedObjects!
{
let capitalAsset : CapitalAsset = property as! CapitalAsset
let marker = GMSMarker.init()
marker.draggable = false
marker.snippet = capitalAsset.address
let location = CLLocationCoordinate2DMake(Double(capitalAsset.latitude!), Double(capitalAsset.longitude!))
marker.position = location
marker.map = mapView
// Update bounds to include marker
bounds.includingCoordinate(marker.position)
}
mapView.animateWithCameraUpdate(GMSCameraUpdate.fitBounds(bounds, withPadding: 50.0))
}
My plotAll function is successfully called and loops through a dozen global locations adding these to the GMSCoordinateBounds.
But the map is not being updated. I was expecting the map view to change when I called animateWithCameraUpdate but it has no effect.
Further information, for debugging I replaced the line
mapView.animateWithCameraUpdate(GMSCameraUpdate.fitBounds(bounds, withPadding: 50.0))
with :
let camera = GMSCameraPosition.cameraWithLatitude(51.48, longitude: 0, zoom: 10)
mapView.camera = camera
This does update my map view so there is no problem with calling my plotAll function, the issue is probably in my use of animateWithCameraUpdate.
I got this to work by replacing :
mapView.animateWithCameraUpdate(GMSCameraUpdate.fitBounds(bounds, withPadding: 50.0))
with:
let camera = mapView.cameraForBounds(bounds, insets:UIEdgeInsetsZero)
mapView.camera = camera;

Failed to set maprect to show all annotations

I have 2 annotations to display on the mapview, but unable to set the maprect to show all of them on screen without requiring users to zoom out.
I tried with showAnnotations but no luck. Anyone has been able to do this in Swift and Xcode 6.1.1?
Here is my code:
class ViewController: UIViewController, MKMapViewDelegate {
#IBOutlet var map: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
var mapView = map
// 1
let point1 = CLLocationCoordinate2D(latitude: 38.915565, longitude: -77.093524)
let point2 = CLLocationCoordinate2D(latitude: 38.890693, longitude: -76.933318)
//2
let annotation = MKPointAnnotation()
annotation.setCoordinate(point1)
annotation.title = "point1"
map.addAnnotation(annotation)
let annotation2 = MKPointAnnotation()
annotation2.setCoordinate(point2)
annotation2.title = "point2"
map.addAnnotation(annotation2)
//3
// option1: set maprect to cover all annotations, doesn't work
var points = [annotation, annotation2]
var rect = MKMapRectNull
for p in points {
let k = MKMapPointForCoordinate(p.coordinate)
rect = MKMapRectUnion(rect, MKMapRectMake(k.x, k.y, 0.1, 0.1))
println("result: x = \(rect.origin.x) y = \(rect.origin.y)")
}
map.setVisibleMapRect(rect, animated: true)
// option 2: using showAnnotations, doesn't work
//map.showAnnotations(points, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
This is what I got currently:
This is what I expected to see:
Thanks for your help.
I finally found out why the pins of the annotations had not been displayed in the visible region of the screen. I think the MapKit framework behaves a bit different than in the previous versions. Since I use autolayout to allow the map to expand to the entire screen for all devices (iPhones, iPad), setVisibleMapRect or mapView.showAnnotations of the map should be invoked in mapViewDidFinishLoadingMap, not in viewDidLoad of the view controller
For example:
func mapViewDidFinishLoadingMap(_ mapView: MKMapView) {
// this is where visible maprect should be set
mapView.showAnnotations(mapView.annotations, animated: true)
}
I had this same problem when I called
viewDidLoad() {
mapView.showAnnotations(myAnnotations, animated: false)
}
However, moving the call to viewDidLayoutSubviews() also seems to fix the problem (not that isInitialLoad is initialized to true in viewDidLoad).
viewDidLayoutSubviews() {
if isInitialLoad {
mapView.showAnnotations(myAnnotations, animated: false)
isInitialLoad = false
}
}
The difference (I think it is an advantage) of putting the call in viewDidLayoutSubviews is that the map hasn't actually displayed yet, so your initial display is that area defined by the annotations. However, it seems that it is called every time the map zooms, so you need to be sure to only call it the first time.
For me using showing annotations after map did finish loading did not work.
func mapViewDidFinishLoadingMap(mapView: MKMapView!) {
// this is where visible maprect should be set
mapView.showAnnotations(mapView.annotations, animated: true)
}
Besides showing the annotation, I needed to calculate polylines to connect the annotations and map finished loading was triggered too early.
Instead I tried mapViewDidFinishRenderingMap and it worked perfectly fine. See example below:
//MARK: - Show all objects after adding them on the map
func mapViewDidFinishRenderingMap(mapView: MKMapView, fullyRendered: Bool) {
mapView.showAnnotations(mapStages, animated: true)
}
You can try this.
I created an extension to show all the annotations using some code from here and there in swift 2.3. This will not show all annotations if they can't be shown even at maximum zoom level.
import MapKit
extension MKMapView {
func fitAllAnnotations() {
var zoomRect = MKMapRectNull;
for annotation in annotations {
let annotationPoint = MKMapPointForCoordinate(annotation.coordinate)
let pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
zoomRect = MKMapRectUnion(zoomRect, pointRect);
}
setVisibleMapRect(zoomRect, edgePadding: UIEdgeInsetsMake(20, 20, 20, 20), animated: true)
}
}