18 Replies
      Latest reply on Dec 19, 2019 1:18 PM by Claude31
      zanfardinom Level 1 Level 1 (0 points)

        I am trying to change the height of a UIView based on which device the user is on. For example, I have created a view with an alpha of 25%. This view is pinned to the top, left, and right of the screen. I need the view to have a height of 44 when viewed on devices that have the cutout at the top (i.e. iPhone 11...etc.) and a height of 22 when viewed on devices that do not have the cutout (i.e. iPhone 8s Plus..etc.).

         

        I am trying to accomplish this by using Vary for Traits in Xcode and not successful (I am sure it's because that is the wrong way to do it. LOL).

        Please let me know if you need additional information or have any questions. I appreciate your time and help in advance.

         

        Thank you,

        mz

        • Re: Help with changing the height of a UIView based on the device
          Claude31 Level 8 Level 8 (7,895 points)

          An idea on how to do it.

           

          1. Detect if there is a notch (cutout)

           

          extension UIDevice {
              var hasNotch: Bool {
                  if #available(iOS 11.0, *) {
                      let bottom = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
                      return bottom > 0
                  } else {
                      // Fallback on earlier versions
                      return false
                  }
              }
          }

           

           

          2. In the ViewController viewDidLoad, adapt the height of the view

          // Declare the IBOutlet

              @IBOutlet weak var viewAtNotch: UIView!

          //  set constraints to the top in IB

           

          // in viewDidLoad

                  if UIDevice.current.hasNotch {
                      viewAtNotch.frame.size.height = 44
                  } else {
                      viewAtNotch.frame.size.height = 22
                  }
            • Re: Help with changing the height of a UIView based on the device
              zanfardinom Level 1 Level 1 (0 points)

              Hi Claude31,

               

              I appreciate the quick response and information.  I tried the example above and the detection always fallsback to no notch.  I am using the simulator and the same return happens for iPhone X or an iPhone 8 (no notch).

               

              Any suggestions?

               

              Thank you,

              mz

                • Re: Help with changing the height of a UIView based on the device
                  Claude31 Level 8 Level 8 (7,895 points)

                  I tested this code in XCode 11.2ß2 and iOS 13.2 simulator

                          print("notch", UIDevice.current.hasNotch)

                   

                  iPhone XS and XS Max => returns true

                  iPhone 8 (no notch). => returns false

                    • Re: Help with changing the height of a UIView based on the device
                      zanfardinom Level 1 Level 1 (0 points)

                      Hi Claude31,

                       

                      Yes, each time I run a different device (notch or no notch) my print message says "without notch".  In addition, if I set top, leading, trailing, and height (gives errors if I don't set height) constraints on the UIView, then the height will not change to what I have set in the code.

                       

                      I am testing code in Xcode 11.3(11C29) and iOS 13.3 simulator.

                       

                      Thank you,

                      mz

                        • Re: Help with changing the height of a UIView based on the device
                          Claude31 Level 8 Level 8 (7,895 points)

                          I tested in Xcode 11.3 (11C29) and iOS 13.3 simulator for iPhone 11 ProMax - 13.3. OSX 10.14.6

                           

                          I get true for notch.

                            • Re: Help with changing the height of a UIView based on the device
                              zanfardinom Level 1 Level 1 (0 points)

                              No doubt it's something I am doing wrong...lol.  Below is my code.

                               

                              ViewController.swif

                              import UIKit
                              
                              class ViewController: UIViewController {
                                 
                                  @IBOutlet weak var viewAtNotch: UIView!
                              //    var viewAtNotch = UIView()
                              
                                  override func viewDidLoad() {
                                      super.viewDidLoad()
                                      // Do any additional setup after loading the view.
                                     
                                      if UIDevice.current.hasNotch {
                                          viewAtNotch.frame.size.height = 44
                                          print("has notch")
                                      } else {
                                          viewAtNotch.frame.size.height = 22
                                          print("without notch")
                                      }
                                  }
                              }

                               

                              UIDevice+Notch.swif

                              import Foundation
                              import UIKit
                              
                              extension UIDevice {
                                  var hasNotch: Bool {
                                      let bottom = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
                                      print(bottom)
                                      return bottom > 0
                                  }
                              }

                               

                              And no matter which device I simulate (from the biggest iPad to the smallest iPhone) it returns "without notch".

                               

                              mz

                                • Re: Help with changing the height of a UIView based on the device
                                  Claude31 Level 8 Level 8 (7,895 points)

                                  What is the result of

                                          print(bottom) 

                                   

                                  And complementing the print:

                                  print("bottom", bottom, "keyWindow", UIApplication.shared.keyWindow)
                                    • Re: Help with changing the height of a UIView based on the device
                                      zanfardinom Level 1 Level 1 (0 points)

                                      The result of print(bottom) is 0.0.

                                       

                                      I updated print per you suggestion to include 'keyWindow'.

                                       

                                      print("bottom", bottom, "keyWindow", UIApplication.shared.keyWindow)

                                       

                                      result:

                                      bottom 0.0 keyWindow nil

                                       

                                      Also, I did not add this before, but 'keyWindow' was deprecated in iOS 13.0.

                                      'keyWindow' was deprecated in iOS 13.0: Should not be used for applications that support multiple scenes as it returns a key window across all connected scenes

                                       

                                      Thank you,

                                      mz

                                        • Re: Help with changing the height of a UIView based on the device
                                          Claude31 Level 8 Level 8 (7,895 points)

                                          I did not notice the deprecation.

                                           

                                          Could try this, credit to.  https://stackoverflow.com/questions/52402477/ios-detect-if-the-device-is-iphone-x-family-frameless

                                           

                                          extension UIDevice {
                                              var hasNotch: Bool {
                                                  if #available(iOS 11.0, *) {
                                                      let top = UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0
                                                      return top > 0
                                                  } else {
                                                      // Fallback on earlier versions
                                                      return false
                                                  }
                                              }
                                          }

                                           

                                           

                                          Note that the double optional chaining ??. is not an error: https://stackoverflow.com/questions/28901893/why-is-main-window-of-type-double-optional

                                            • Re: Help with changing the height of a UIView based on the device
                                              zanfardinom Level 1 Level 1 (0 points)

                                              Still no go.  Not sure what I am doing for it not to work.   Below is the updated code.

                                               

                                              UIDevice+Notch.swif

                                              import Foundation
                                              import UIKit
                                              
                                              extension UIDevice {
                                                  var hasNotch: Bool {
                                              //        return UIApplication.shared.delegate?.window??.safeAreaInsets.bottom ?? 0 > 0
                                                      let top = UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0
                                                      print("top" top)
                                                      return top > 0
                                                  }
                                              }

                                               

                                              ViewController.swif

                                              import UIKit
                                              
                                              
                                              
                                              class ViewController: UIViewController {
                                              
                                                  @IBOutlet weak var viewAtNotch: UIView!
                                                  @IBOutlet weak var statusBarBackgroundHeight: NSLayoutConstraint!
                                              //    var viewAtNotch = UIView()
                                              
                                                  override func viewDidLoad() {
                                                      super.viewDidLoad()
                                                      // Do any additional setup after loading the view.
                                                      if UIDevice.current.hasNotch {
                                                          self.statusBarBackgroundHeight.constant = 44
                                              //            viewAtNotch.frame.size.height = 44
                                                          print("has notch")
                                                      } else {
                                                          self.statusBarBackgroundHeight.constant = 22
                                              //            viewAtNotch.frame.size.height = 22
                                                          print("without notch")
                                                      }
                                                  }
                                              }

                                               

                                               

                                              Results for iPhone 11 Pro Max running 13.3 are:

                                              top 0.0
                                              without notch
                                                • Re: Help with changing the height of a UIView based on the device
                                                  Claude31 Level 8 Level 8 (7,895 points)

                                                  I don't understand either.

                                                  Most likeley, UIApplication.shared.delegate?.window. is nil

                                                  Could you check if UIApplication.shared.delegate is nil or not ?

                                                   

                                                  Does the AppDelegate class contains this :

                                                   

                                                  @UIApplicationMain
                                                  class AppDelegate: UIResponder, UIApplicationDelegate {
                                                  
                                                      var window: UIWindow?

                                                   

                                                  Are you running on simulator or device ?

                                                   

                                                  I tested with 13.2 target, still works.

                                                   

                                                  I may have found the difference.

                                                  Tested on a project with SceneDelegate.

                                                   

                                                  And then, notch is false, even on X11 Pro.

                                                   

                                                  So, I replaced by this extension:

                                                  extension UIDevice {
                                                      var hasNotch: Bool {
                                                          if #available(iOS 11.0, *) {
                                                              if UIApplication.shared.windows.count == 0 { return false }          // Should never occur, but…
                                                              let top = UIApplication.shared.windows[0].safeAreaInsets.top
                                                              return top > 20          // That seem to be the minimum top when no notch…
                                                          } else {
                                                              // Fallback on earlier versions
                                                              return false
                                                          }
                                                      }
                                                  }

                                                  Credit:

                                                  h ttps://www.reddit.com/r/swift/comments/cap2r4/how_to_access_uiwindow_from_scenedelegate_in_ios/

                                                   

                                                  That seems to work.

                                                    • Re: Help with changing the height of a UIView based on the device
                                                      zanfardinom Level 1 Level 1 (0 points)

                                                      The updated extension code seems to do the trick.  I did update return top > 20 to return top > 24.  This will include the iPad.

                                                       

                                                      credit MarekR - https://stackoverflow.com/questions/52402477/ios-detect-if-the-device-is-iphone-x-family-frameless

                                                       

                                                      Thanks for the help!  Happy Holidays!

                                                       

                                                      mz

                                                        • Re: Help with changing the height of a UIView based on the device
                                                          zanfardinom Level 1 Level 1 (0 points)

                                                          Claude31,

                                                           

                                                          I have one additional and final question.  I want the bar to show behind the status bar in portrait mode, but not in landscape mode for all iPhones.  I want to show the bar behind the status bar in portrait and landscape for iPads.  The code below (for the most part) works for iPhones that do not have a notch and iPads.  iPhones with a notch work fine in portrait and landscape, except when you go back to portrait the bar's height is set to 22 because it does not detect the notch.  I have to open another view and go back for the extension code to be read again.  I have spent time trying different things and searching.  Thoughts/suggestions?

                                                           

                                                          UIDevice+Notch.swift

                                                          import Foundation
                                                          import UIKit
                                                          
                                                          extension UIDevice {
                                                              var hasNotch: Bool {
                                                                  if UIApplication.shared.windows.count == 0 { return false }
                                                                  let top = UIApplication.shared.windows[0].safeAreaInsets.top
                                                                  print("top", top)
                                                                  print("windows", UIApplication.shared.windows)
                                                                  return top > 24
                                                              }
                                                          }

                                                           

                                                          ViewController.swift

                                                          import UIKit
                                                          
                                                          class ViewController: UIViewController {
                                                             
                                                              @IBOutlet weak var viewAtNotch: UIView!
                                                              @IBOutlet weak var statusBarBackgroundHeight: NSLayoutConstraint!
                                                          
                                                              override func viewDidLoad() {
                                                                  super.viewDidLoad()
                                                                  // Do any additional setup after loading the view.
                                                                 
                                                                  if UIDevice.current.hasNotch {
                                                                      self.statusBarBackgroundHeight.constant = 44
                                                                      print("has notch")
                                                                  } else {
                                                                      self.statusBarBackgroundHeight.constant = 22
                                                                      print("without notch")
                                                                  }
                                                              }
                                                             
                                                              override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
                                                                  super.viewWillTransition(to: size, with: coordinator)
                                                                 
                                                                  if UIDevice.current.orientation.isLandscape {
                                                                      print("Landscape")
                                                                      if UIDevice.current.hasNotch {
                                                                          self.statusBarBackgroundHeight.constant = 0
                                                                          print("Device is in Landscape - has a notch")
                                                                      } else {
                                                                          if UIDevice.current.userInterfaceIdiom == .pad {
                                                                              self.statusBarBackgroundHeight.constant = 22
                                                                              print("Device is in Landscape and is an iPad - no notch")
                                                                          } else {
                                                                              self.statusBarBackgroundHeight.constant = 0
                                                                              print("Device is in Landscape and not an iPad - no notch")
                                                                          }
                                                                      }
                                                                  } else {
                                                                      print("Portrait")
                                                                      if UIDevice.current.hasNotch {
                                                                          self.statusBarBackgroundHeight.constant = 44
                                                                          print("Device is in Portrait - has a notch")
                                                                      } else {
                                                                          self.statusBarBackgroundHeight.constant = 22
                                                                          print("Device is in Portrait - no notch")
                                                                      }
                                                                  }
                                                              }
                                                          }
                                  • Re: Help with changing the height of a UIView based on the device
                                    KMT Level 9 Level 9 (15,425 points)

                                    Seen this (lengthy/bit dated?) SO thread? Good info on working w/the notch, especially if you're stuck simulator testing only...

                                     

                                    https://stackoverflow.com/questions/46192280/detect-if-the-device-is-iphone-x/47067296