I'm trying to add a search bar to a navigation map for MapBox on iOS, but having some trouble. I'm trying to do it programmatically in this case, as I don't have a great handle on storyboard. I've tried messing around with the zIndex as well, but still no search bar shows up for me.
Here's the code I've got so far:
class ViewController: UIViewController, UISearchBarDelegate, MGLMapViewDelegate {
var mapView: NavigationMapView!
lazy var directions: DirectionsManager = DirectionsManager()
var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
// Setup mapbox
let styleURL = URL(string: "style")
mapView = NavigationMapView(frame: view.bounds, styleURL: styleURL)
view.addSubview(mapView)
mapView.delegate = self
mapView.showsUserLocation = true
mapView.setUserTrackingMode(.follow, animated: true)
mapView.localizeLabels()
self.searchBar = UISearchBar()
mapView.addSubview(searchBar)
}
#erikpartridge, It's not an issue with mapbox, you need to set frame for UISearchBar like the below,
self.searchBar = UISearchBar(frame: CGRect(x: 15, y: 50, width: (view.bounds.width-30), height: 50))
mapView.addSubview(searchBar)
Related
PNG Tiles are showing incorrect color and transparency on iOS. Transparent areas show up as a semi-transparent white. The same tile set shows up correctly on Android and web browser, so I don't believe it is an issue is with the tiles themselves. Here's my Swift code:
class ViewController: UIViewController {
#IBOutlet weak var mapView: GMSMapView!
override func viewDidLoad() {
super.viewDidLoad()
let camera = GMSCameraPosition.camera(withLatitude: 30.00, longitude: -90, zoom: 7.0)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
view = mapView
// Implement GMSTileURLConstructor
let urls: GMSTileURLConstructor = { (x, y, zoom) in
let url = "https://aerocast.s3.amazonaws.com/radar/klix/lixtileskml/\(zoom)/\(x)/\(y).png"
return URL(string: url)
}
let tilelayer = GMSURLTileLayer(urlConstructor: urls)
tilelayer.zIndex = 100
tilelayer.map = mapView
tilelayer.opacity = 1.0
}
}
I've looked for some way to adjust the color properties of the tilelayer, but have not been able to find anything.
The issue was specific to the iOS emulator on xcode. The issue is not present on a physical iOS device. I brought up the problem to Google Maps support and they were able to replicate the problem and are looking into it.
I think there is some problem with view hierarchy
class ViewController: UIViewController {
#IBOutlet weak var mapView: GMSMapView!
override func viewDidLoad() {
super.viewDidLoad()
let camera = GMSCameraPosition.camera(withLatitude: 30.00, longitude: -90, zoom: 7.0)
self.mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
self.view.addSubview(mapView)
// Define constraints (i.e position in the parent view), example for full screen ones
mapView.translatesautoresizingmaskintoconstraints = false
mapView.topAnchor.constraint(equalToSystemSpacingBelow: view.topAnchor).isActivate = true
mapView.bottomAnchor.constraint(equalToSystemSpacingBelow: view.bottomAnchor).isActivate = true
mapView.leftAnchor.constraint(equalToSystemSpacingBelow: view.leftAnchor).isActivate = true
mapView.rightAnchor.constraint(equalToSystemSpacingBelow: view.rightAnchor).isActivate = true
// Implement GMSTileURLConstructor
let urls: GMSTileURLConstructor = { (x, y, zoom) in
let url = "https://aerocast.s3.amazonaws.com/radar/klix/lixtileskml/\(zoom)/\(x)/\(y).png"
return URL(string: url)
}
let tilelayer = GMSURLTileLayer(urlConstructor: urls)
tilelayer.zIndex = 100
tilelayer.map = mapView
tilelayer.opacity = 1.0
}
}
This question already has answers here:
Programmatically Added Constraint Not Working
(2 answers)
Closed 2 years ago.
I am trying to set up the map view programmatically and i have set up the constraints down below but when i run the simulator it is just showing a blank screen. I want to pin the map view to the top,bottom,left,right in the view.
class ViewController: UIViewController {
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.view.backgroundColor = .white
configureScreen()
}
let map: MKMapView = {
let map = MKMapView()
map.backgroundColor = .black
return map
}()
func configureScreen(){
view.addSubview(map)
NSLayoutConstraint.activate([
map.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor,constant: 100),
map.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor,constant: 0),
map.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor,constant: 0),
map.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor,constant: 0)
])
}
}
Because you forgot to say
map.translatesAutoresizingMaskIntoConstraints = false
This is my first entry. I am new in app designing and from Germany, but I still hope you can understand my problem. I used Xcode 11 and Swift 5.
I am using a page control and scroll view to switch between images in one screen. It looks good on the iPhone 11 but on the iPhone 8 the width and height of the images is too great, which is why part of the first image can still be seen when the page control is on the second segment. The same happens for the with the second image and the third segment.This hopefully shows the problem.
Is there a way to fit the images to the screen size?
This is my code:
```
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var pageControl: UIPageControl!
var Pages: [String] = ["Page1","Page2","Page3"]
var frame = CGRect.zero
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
pageControl.numberOfPages = Pages.count //
setupScreens()
scrollView.showsHorizontalScrollIndicator = false
scrollView.showsVerticalScrollIndicator = false
scrollView.isPagingEnabled = true
scrollView.delegate = self
}
func setupScreens() {
for index in 0..<Pages.count {
// 1.
frame.origin.x = scrollView.frame.size.width * CGFloat(index)
frame.size = scrollView.frame.size
// 2.
let imageView = UIImageView(frame: frame)
imageView.image = UIImage(named: Pages[index])
self.scrollView.addSubview(imageView) }
// 3.
scrollView.contentSize = CGSize(width: (scrollView.frame.size.width * CGFloat(Pages.count)), height: scrollView.frame.size.height)
scrollView.delegate = self
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageNumber = scrollView.contentOffset.x / scrollView.frame.size.width
pageControl.currentPage = Int(pageNumber)
}
}
```
Your code is totally working fine except calling setupScreens() method in viewDidLoad().
call that method in viewDidLayoutSubviews so that it will get proper frame of scrollView.
override func viewDidLayoutSubviews() {
setupScreens()
}
Download demo from here
Update: Dose it have to do anything with language? as my app is sporting English and Arabic.
Hi everyone I am struggling with this since days and I have tried everything but can not find any solution, the problem is when I run the app through xCode it all works fine like in the following screenshot.
Then when i unplug the device and reopen the app it stops working, the app is running fine but i dont see any map but just the markers like the following screenshot.
Any help will be appreciated.
AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
GMSServices.provideAPIKey(googleApiKey)
GMSPlacesClient.provideAPIKey(googleApiKey)
return true
}
ViewController
//Step 1
#IBOutlet weak var mapview: GMSMapView!
//Step 2
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.mapview.settings.scrollGestures = true
self.mapview.settings.zoomGestures = true
self.mapview.isMyLocationEnabled = true
self.mapview.settings.myLocationButton = true
self.mapview.delegate = self
self.mapview.layoutIfNeeded()
}
}
//Step 3 After we have the current location items are loaded from server by user location and the markers are added in GetBusinesses function
extension ItemsList: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
guard status == .authorizedWhenInUse else {
return
}
self.locationManager.startUpdatingLocation()
self.mapview.camera = GMSCameraPosition(target: (self.locationManager.location?.coordinate)!, zoom: 14, bearing: 0, viewingAngle: 0)
self.GetBusinesses(data: "&isOpen=2&cat=\(Prefrences.getSelectedCategoryId())")
}
}
to show map in custom views you have to do it that way,
let camera = GMSCameraPosition.camera(withLatitude: lat , longitude: long, zoom: 15.0)
let mapView = GMSMapView.map(withFrame: CGRect(x: 2, y: 2, width: self.MapView.frame.width - 4, height: self.MapView.frame.height - 2), camera: camera)
self.MapView.addSubview(mapView)
self.MapView.clipsToBounds = true
self.MapView.contentMode = .center
you need to create a mapView using the created mapView on the storyboard frame and add it as a subView in the main MapView you created
Okay so after struggling many days and trying every stupid possible way to fix it, I finally found a solution to it. The main problem was if your app is supporting multiple languages then google map will show this kind of behaviour. Following are the steps to fix it.
Step 1:
If you have the GMSMapView view in your viewController, break the outlets of your GMSMapView since it will be created dynamically.
Step 2:
Set the application language as per the user settings.
Step 3:
Create custom GMSMapView object set delegate methods and other necessary settings and add it to its container.
That's it, you are good to go. What I understood from this is that you have to set your app language first before creating the GMSMapView (I can be wrong as well). If anyone knows why this method is working kindly explain it.
//Our Custom MapView Var
var mapview: GMSMapView!
//View viewDidLoad() function
override func viewDidLoad() {
super.viewDidLoad()
/*
TODO:
Get selected language from preferences and set accordingly.
*/
UserDefaults.standard.set(["en"], forKey: "AppleLanguages")
UserDefaults.standard.synchronize()
let camera = GMSCameraPosition.camera(withLatitude: 55.277397,
longitude: 25.199514,
zoom:12)
self.mapview = GMSMapView.map(withFrame: self.mMapContainer.bounds, camera: camera)
self.mapview.delegate = self
self.mapview.isMyLocationEnabled = true
self.mapview.settings.myLocationButton = true
self.mapview.isMyLocationEnabled = true
self.mapview.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mMapContainer.addSubview(self.mapview)
}
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)
}
}