How can I turn the MKMapView for dark mode? - swift

How can I change the map to dark mode from iOS 13?
I have opt-out from UserInterfaceStyle so system-wide colors will not apply to me, so I'll do it manually.
I've seen this video from apple WWDC2019 - Session 236, at 8:19s but that's for snapshots and I didn't get it.
Actually I was trying something like:
private var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapView.backgroundColor = .black
}
but it doesn't change the theme or appearance or the traitCollection to dark.
Any suggestion?

This is what you need on the viewDidLoad
if #available(iOS 13.0, *) {
self.overrideUserInterfaceStyle = .dark
}

Setting overrideUserInterfaceStyle on viewDidLoad method will force that view controller to use the desired mode you specify.
if #available(iOS 13.0, *) {
overrideUserInterfaceStyle = .light
}
MapSnapShot
if you are trying to take a snapshot and confused with output image colour Use
if #available(iOS 13.0, *) {
mapSnapshotOptions.traitCollection = traitCollection
}
Full code for a MKMapSnapshotter
func mapCamera(location : CLLocationCoordinate2D )-> MKMapSnapshotter {
let mapSnapshotOptions = MKMapSnapshotter.Options()
let region = MKCoordinateRegion(center: location, latitudinalMeters: 500, longitudinalMeters: 500)
mapSnapshotOptions.region = region
mapSnapshotOptions.scale = UIScreen.main.scale
mapSnapshotOptions.size = AppConstants.Size.mapDetailView
mapSnapshotOptions.showsBuildings = true
mapSnapshotOptions.showsPointsOfInterest = true
if #available(iOS 13.0, *) {
mapSnapshotOptions.traitCollection = traitCollection
}
return MKMapSnapshotter(options: mapSnapshotOptions)
}

In case you got here searching for a macOS solution (like me), simply update the appearance property on MKMapView:
if #available(OSX 10.14, *) {
mapView.appearance = NSAppearance(named: .darkAqua) // .aqua for default mode
}

Related

Google Maps iOS SDK GMSURLTileLayer displaying incorrect color/transparency

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
}
}

Making Cocoa NSWindow translucent hides storyboard elements

In my app delegate I make my window translucent with the following code:
func applicationDidFinishLaunching(_ aNotification: Notification) {
let visualEffect = NSVisualEffectView()
visualEffect.translatesAutoresizingMaskIntoConstraints = false
visualEffect.material = .dark
visualEffect.state = .active
visualEffect.wantsLayer = true
visualEffect.layer?.cornerRadius = 16.0
NSApplication.shared.mainWindow?.titleVisibility = .hidden
NSApplication.shared.mainWindow?.styleMask.remove(.titled)
NSApplication.shared.mainWindow?.backgroundColor = .clear
NSApplication.shared.mainWindow?.isMovableByWindowBackground = true
NSApplication.shared.mainWindow?.contentView?.addSubview(visualEffect)
guard let constraints = NSApplication.shared.mainWindow?.contentView else {
return
}
visualEffect.leadingAnchor.constraint(equalTo: constraints.leadingAnchor).isActive = true
visualEffect.trailingAnchor.constraint(equalTo: constraints.trailingAnchor).isActive = true
visualEffect.topAnchor.constraint(equalTo: constraints.topAnchor).isActive = true
visualEffect.bottomAnchor.constraint(equalTo: constraints.bottomAnchor).isActive = true
}
The problem with this is that every element in the storyboard is no longer visible. How can I fix this? Thanks
You need to add all your UI to the NSVisualEffectView as subviews or move the NSVisualEffectView to the back of the view hierarchy:
NSApplication.shared.mainWindow?.contentView?.addSubview(visualEffect, positioned: .below, relativeTo: nil)
Update:
I created a new macOS project in Xcode and added a label on the view. Then I pasted your code and the only thing I changed was the line of code above. It works.

UIscrollview issue with iPhone X

I am having a horizontal UIScrollview in my xib file. Scrollview looks great in all devices except iPhone X, XS and XR.
It looks good in iPhone 8
iPhone X
I have tried all the possible solutions, Unchecked the under top bar, under bottom bar, auto resize subviews,nothing works for me. iPhone X always looks the same. Top constraint of the scrollview is set to safe area. I am using xib file here.
if #available(iOS 11.0, *) {
scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.never
} else {
self.automaticallyAdjustsScrollViewInsets = false
edgesForExtendedLayout = []
// Fallback on earlier versions
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.scrollView.contentSize = CGSize(width: self.lectureTable.frame.size.width , height: self.scrollView.frame.size.height)
self.automaticallyAdjustsScrollViewInsets = false
}
Please shed some light. Thanks a ton.
I have solved it by myself. Inside my scroll view, I have used UIView.
var hasTopNotch: Bool {
if #available(iOS 11.0, *) {
return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
}
return false
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
var topbarHeight: CGFloat {
return UIApplication.shared.statusBarFrame.size.height + (self.navigationController?.navigationBar.frame.height ?? 0.0)
}
if hasTopNotch{
let window = UIApplication.shared.keyWindow
if #available(iOS 11.0, *) {
let topPadding = window?.safeAreaInsets.top
self.customView.frame.size.height = UIScreen.main.bounds.height - (topbarHeight + topPadding!)
} else {
// Fallback on earlier versions
}
}else{
let NavBarHeight = self.navigationController!.navigationBar.frame.height + UIApplication.shared.statusBarFrame.height
self.customView.frame.size.height = UIScreen.main.bounds.height - NavBarHeight
}
}
This works great in all the devices.

Images and Darkmode not switching

In a couple of my apps, I have an image covering the view in the background. In my asset catalog, my image has an Any, light and dark variation. In iOS 13, when I launch the app, the correct light or dark mode image is displayed according to the mode set. However, when I switch the mode while the app is running, the image does not change. All other properties change (colors etc) for all controls, but not the image.
I have tried the following with a layoutIfNeeded() and/or layoutSubviews() inside the traitCollectiosnDidChange block:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
guard let previousTraitCollection = previousTraitCollection else {return}
if #available(iOS 13.0, *) {
if previousTraitCollection.hasDifferentColorAppearance(comparedTo: traitCollection) {
print("Changed mode")
self.view.layoutIfNeeded()
self.view.layoutSubviews()
}
}
}
and the Change mode is definitely triggered but the layout does not change.
Is there a way to make sure that the image also displays the correct one?
OK. To answer my own question. I was applying .withHorizontallyFlippedOrientation() to my image and setting it in ViewDidLoad. When I changed the trait color mode, this image was not getting change.
The solution was to to reset the image AND the flip property when the differentColorAppearance triggers. Like this
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
guard let previousTraitCollection = previousTraitCollection else {return}
if #available(iOS 13.0, *) {
if previousTraitCollection.hasDifferentColorAppearance(comparedTo: traitCollection) {
image2.image = UIImage(named: "CourseImage")?.withHorizontallyFlippedOrientation()
}
}
}

Google Maps strange behavior swift 4 ios

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)
}