iOS 11 Layout guidance about safe Area for iPhone x
With iOS11 (and the appearance of iPhoneX) Apple introduced the Safe Area Layout Guide to adapt your views to the iPhoneX.
The Safe Area is the area of the screen that is not overlapped by the notch or the home indicator.
To avoid the issue you are experiencing you have to change your noView's top constraint for iOS11:
if #available(iOS 11, *) {
let guide = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
noView.topAnchor.constraint(equalTo: guide.topAnchor)
])
} else {
NSLayoutConstraint.activate([
noView.topAnchor.constraint(equalTo: currentViewController.topLayoutGuide.bottomAnchor)
])
}
NSLayoutConstraint.activate([
noView.leadingAnchor.constraint(equalTo: currentViewController.view.leadingAnchor),
noView.trailingAnchor.constraint(equalTo: currentViewController.view.trailingAnchor),
noView.heightAnchor.constraint(equalToConstant: 65)
])
Unfortunately that is not all. Because now your noView
moves down on iPhone X, but the status bar does not have a red background anymore. You have add a red background color behind the status bar:
You could make things a lot easier by using a UINavigationController (with a red navigation bar):
With this approach you don't have to set any constraints! The systems does all the adjustments for you automatically.
iPhone X - safe area layout guides - I want my app display on full screen, not only in the safe area
I resolved my issue. The application was not displaying in full screen because of missing launch image in my assets for iPhone XR. Because of this iOS was falling back to the closest launch image keeping aspect ratio, thus defining the application size.
The second issue (not loading the image, displaying some default splash screen insead) - removing the app from device and installing from scratch helped.
Thanks everyone involved :)
How to specify offset from safe area in iOS below 11?
The versions of iOS before iOS 11 do not have safe area insets. These started with the introduction of iPhone X (shipped with iOS 11).
There is no need to compensate for these insets on older versions of iOS.
This is what your code should look like for backwards compatibility
var frame: CGRect
if #available(iOS 11.0, *) {
frame = CGRect(x:0,
y: self.view.safeAreaInsets.top + 16,
width: 100,
height: 50)
} else {
frame = CGRect(x:0,
y: topLayoutGuide.length + 16,
width: 100,
height: 50)
}
let customView = CustomView(frame: frame)
self.view.addSubview(customView)
Note:
If you are using the Safe Area Layout Guides for iOS 11, there are the topLayoutGuide
and bottomLayoutGuide
properties on UIViewController available for iOS 7 - 10.
iOS 11 Swift 4 iPhone X Safe Area Support of full screen ScrollView
You can do this using safe area layout guide
and get more info using the link:
https://medium.com/rosberryapps/ios-safe-area-ca10e919526f
You can also do this without safe area: I have prepared a demo for you and in this demo, we have three view controllers added on scroll view and scroll view is added on another view controller(ContainerViewController
)
ContainerViewController
:
import UIKit
class ContainerViewController: UIViewController, UIScrollViewDelegate {
@IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let V1 = self.storyboard?.instantiateViewController(withIdentifier: "first")
self.addChildViewController(V1!)
self.scrollView.addSubview(V1!.view)
V1?.didMove(toParentViewController: self)
V1?.view.frame = scrollView.bounds
let V2 = self.storyboard?.instantiateViewController(withIdentifier: "second")
self.addChildViewController(V2!)
self.scrollView.addSubview(V2!.view)
V2?.didMove(toParentViewController: self)
V2?.view.frame = scrollView.bounds
let V3 = self.storyboard?.instantiateViewController(withIdentifier: "third")
self.addChildViewController(V3!)
self.scrollView.addSubview(V3!.view)
V3?.didMove(toParentViewController: self)
V3?.view.frame = scrollView.bounds
var V1Frame: CGRect = V1!.view.frame
V1Frame.origin.y = 0
V1?.view.frame = V1Frame
var V2Frame: CGRect = V2!.view.frame
V2Frame.origin.y = (self.view.frame.height)
V2?.view.frame = V2Frame
var V3Frame: CGRect = V3!.view.frame
V3Frame.origin.y = (self.view.frame.height)*2
V3?.view.frame = V3Frame
}
override func viewDidLayoutSubviews() {
scrollView.contentSize = CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height*3)
}
}
Note: Remove top and bottom constraint from the safe area and add them from
SuperView
(for Scroll view, InnerView(FirstVC, SecondVC, ThirdVC))`
You can check all the functionality and constraints of the demo project. Download URL: https://www.dropbox.com/s/4ovfqmrtwt2i8yi/StackOverflow.zip?dl=0
I have tested the demo in iPhoneX
and iPhone6
and iPhone8+
Screenshots are below:
Safe area layout guides in xib files - iOS 10
There are some issues with safe area layout and backwards compatibility. See my comment over here.
You might be able to work around the issues with additional constraints like a 1000 priority >= 20.0 to superview.top and a 750 priority == safearea.top. If you always show a status bar, that should fix things.
A better approach may be to have separate storyboards/xibs for pre-iOS 11 and iOS-11 and up, especially if you run into more issues than this. The reason that's preferable is because pre-iOS 11 you should layout constraints to the top/bottom layout guides, but for iOS 11 you should lay them out to safe areas. Layout guides are gone. Laying out to layout guides for pre-iOS 11 is stylistically better than just offsetting by a min of 20 pixels, even though the results will be the same IFF you always show a status bar.
If you take this approach, you'll need to set each file to the correct deployment target that it will be used on (iOS 11, or something earlier) so that Xcode doesn't give you warnings and allows you to use layout guides or safe areas, depending. In your code, check for iOS 11 at runtime and then load the appropriate storyboard/xibs.
The downside of this approach is maintenance, (you'll have two sets of your view controllers to maintain and keep in sync), but once your app only supports iOS 11+ or Apple fixes the backward compatibility layout guide constraint generation, you can get rid of the pre-iOS 11 versions.
By the way, how are you displaying the controller that you're seeing this with? Is it just the root view controller or did you present it, or..? The issue I noticed has to do with pushing view controllers, so you may be hitting a different case.
Related Topics
Having App Restart Itself When It Detects Change to Privacy Settings
How to Remove Border from Segmented Control
How to Set Http Header Fields in Objective-C
How to Set an Nscalendarunitminute Repeatinterval on iOS 10 Usernotifications
How to Get Index Path of Cell on Switch Change Event in Section Based Table View
Audiokit: Using the New Aksequencer with Any Variety of the Callback Instruments
Wkwebview Causes My View Controller to Leak
No Suitable Records Were Found Verify Your Bundle Identifier Is Correct
Main.Async VS Main.Sync() VS Global().Async in Swift3 Gcd
Exception Type: Exc_Crash (Sigabrt)
Swift iOS9 New Contacts Framework - How to Retrieve Only Cncontact That Has a Valid Email Address
How to Specify a Platform Target When Running Swift Test from the Cli
How to Force Uiviewcontroller Orientation