Updating your GUI for the iPhone X and other “Notched” Devices
Updated 5 months ago
40.0 K
Learn how to make your GUI compliant with Safe Areas on “notched” mobile devices such as the iPhone X and Pixel 3 XL
When the iPhone X was released on 3 Nov 2017, it brought with it a completely new interface paradigm - the sensor housing (or “notch” as most people call it) and the Home indicator. With these two interface elements, Apple changed the face of mobile GUI design forever. Ever since then, the advent of the iPhone Xs, iPhone Xs Max, Google Pixel 3 XL and other notched Android phones have proven that the notch is most definitely here to stay.
If you have ever held an iPhone X in your hand, it certainly is a wonder to behold. It’s a truly beautiful and innovative device, with its full end-to-end screen and smooth, curved edges. However, with this beauty and innovation comes a price: added development time...
What does this mean for you as a mobile developer? Well, it means you’ll have to adapt your GUI to deal with it in future game releases and updates to existing games. Apple has already set recommendations in their submission guidelines and Google will no doubt follow suit once notches (they call them “cutouts”) are officially supported by the SDK in Android 9 (Pie).
In addition to the notch, many new phones are skewing the traditional aspect ratio of 16:9 for a smartphone and 4:3 for a tablet. The iPhone X, for example, has an aspect ratio of approximately 19.5:9, and similar notched Android phones may have anything between 18:9 and 19:9!
I will cover how to deal with all of these factors in this article, using Unity.

Screen Safe

At the core of the solution is the “screen safe” area. Unity 2017.2.1 added an interface to query this area at runtime: Screen.safeArea. The original release included support for iOS. Later, Unity 2018.3.0 extended support for notched devices running Android 9.0 and above (this was not backported into the 2017.4 LTS).
Screen.safeArea returns a Rect (x, y, width, height) of the safe area’s bounds in device pixels. Note that the values returned will be device-specific and orientation specific. So, it needs to be queried and handled on-the-fly and account for device rotation at run-time (between portrait and landscape).
We can write a MonoBehaviour script for a GUI element that constantly checks if the safe area has changed and applies any changes to the attached UI panel if so (via its RectTransform).
Note: A link to download all scripts and resources from this article is available at the bottom of the page.
using UnityEngine; public class SafeArea : MonoBehaviour { RectTransform Panel; Rect LastSafeArea = new Rect (0, 0, 0, 0); void Awake () { Panel = GetComponent<RectTransform> (); Refresh (); } void Update () { Refresh (); } void Refresh () { Rect safeArea = GetSafeArea (); if (safeArea != LastSafeArea) ApplySafeArea (safeArea); } Rect GetSafeArea () { return Screen.safeArea; } void ApplySafeArea (Rect r) { LastSafeArea = r; // Convert safe area rectangle from absolute pixels to normalised anchor coordinates Vector2 anchorMin = r.position; Vector2 anchorMax = r.position + r.size; anchorMin.x /= Screen.width; anchorMin.y /= Screen.height; anchorMax.x /= Screen.width; anchorMax.y /= Screen.height; Panel.anchorMin = anchorMin; Panel.anchorMax = anchorMax; Debug.LogFormat ("New safe area applied to {0}: x={1}, y={2}, w={3}, h={4} on full extents w={5}, h={6}", name, r.x, r.y, r.width, r.height, Screen.width, Screen.height); } }
To give you a solid understanding of what’s going on here, it’s best to demonstrate this in a test scene. We can create a base UI Canvas with the following properties:
  • Canvas/Render Mode = “Screen Space - Overlay”
  • Canvas Scaler/UI Scale Mode = “Scale With Screen Size”
  • Canvas Scaler/Match (Width-Height) = 0.5
This allows us to have a generic canvas that will scale evenly on both axes and work with any device resolution and aspect ratio.
Inside the Canvas, we can create some basic shapes to help us visualize the safe area:
  1. A full screen background image for visibility purposes (Anchor 0,0 to 1,1; Pivot 0.5,0.5)
  2. As a child of the background, a safe screen image with the safe area script attached (same anchor and pivot)
  3. As children of the safe area image, four children that anchor to each corner, with different colors
For testing in the Editor, we will also need to create two new aspect ratios that emulate the iPhone X:
  • 19.5:9 (or 195:90)
  • 9:19.5 (or 90:195)
The following images show us what it looks like on an iPhone X with no safe area versus having a safe area applied. Note that behind the GUI you are seeing the horizon of the default Unity skybox.
As you can see, on the iPhone X, the safe area pushes the GUI into the top and bottom in portrait mode, and pushes into the left, bottom and right sides in landscape mode. Note that there is no Portrait Upside Down mode on the iPhone X. If you physically rotate the device upside down, it remains in Portrait Up mode. This is an intended feature of the device.
At the bottom of each screen is a software-rendered black bar that Apple calls the “Home indicator.” Swiping up on the Home indicator returns the user to the Home screen. This replaced the physical Home button featured on previous iPhone devices. Android 9.0’s software-rendered Home button provides similar functionality and more.
Note: Unity 2017.3 and above includes an option in the iOS Player Settings to “Hide home button on iPhone X.” This does not hide the Home indicator permanently, but rather performs an “auto-hide” function - whenever a tap is detected anywhere on the screen, the Home indicator will re-appear, then fade out after a few moments. This can be very distracting while playing a game, so it is not recommended. It is only recommended for video-player like applications. Also, regardless of whether this option is turned on or off, the safe area will remain the same (the bottom margin does not change).

Case Study 1: No Background

For our first case study, we’ll look at a full screen main menu interface with buttons anchored to various edges of the screen. Note that these buttons all float in the scene with no full screen GUI background. Here is what is looks like without screen safe applied.
As you can see, we have several problems that violate the Apple user interface guidelines:
1. Portrait Mode:
  • Critical GUI elements at the top of screen are partially hidden by the notch
  • Critical GUI elements at the bottom of screen are overlapping the Home indicator
2. Landscape Mode:
  • Critical GUI elements on the left are partially hidden by the notch
  • Critical GUI elements on the right are outside the screen safe area
  • Critical GUI elements on the bottom are overlapping the Home indicator
In this case, “critical GUI elements” refer to buttons or important text information that are required to operate the game.
This is the easiest case to fix. We simply drag the SafeArea.cs script onto the top-level Main Menu panel. Here is the result:

Case Study 2: Full Screen Background

In this case we have a submenu - an options screen - that contains a full screen background image. If we apply the safe area script to the top-level panel as we did in Case Study 1, here is what it looks like:
Our buttons and text are correctly within the safe area; however, we also have the light blue background conforming to the screen safe area, which doesn’t look nice at all. We want the background to fill the whole screen, ignoring the safe area.
To fix this, we need to create an intermediate panel between the background image and its children, then attach the safe area script to this panel. Here is what the hierarchy looks like:
Here is the result:

Case Study 3: Complex XY Layout

What happens when we have a more complex layout like this?
In this case, we want the horizontal stripes in the middle to stretch to full width, but have their buttons and text conform to screen safe. In addition, we want the bottom row of buttons to conform to screen safe. How do we do this?
We need to add an option on our safe area script to conform to the X- or Y-axis independently. On the child of each horizontal stripe (PnlIncentive), we add the safe area script and only check Conform X. On the parent panel of the bottom row (PnlSafe), we add another instance of the safe area script with both Conform X and Y checked. Here is what the hierarchy looks like in the Editor:
Here is what it looks like in the game:
Using the Conform X/Y technique in different combinations will allow us to cover any other special cases we encounter. Sometimes it just takes a little planning and head-scratching before you figure it out ;)

Editor Simulation

Now for the juicy part. When rapidly iterating and testing an interface, we certainly don’t want to be building to the device or simulator every time, which can take minutes or more depending on the size of your project. We want to be able to test things out quickly and efficiently in the Editor. To do this, we can extend the script to simulate a safe area, and add a hotkey to toggle the safe area on or off at runtime.
Using the safe area pixel coordinates returned from the iPhone X, we can normalize and save these values into the script for simulation.
public enum SimDevice { None, iPhoneX } public static SimDevice Sim = SimDevice.None; Rect[] NSA_iPhoneX = new Rect[] { new Rect (0f, 102f / 2436f, 1f, 2202f / 2436f), // Portrait new Rect (132f / 2436f, 63f / 1125f, 2172f / 2436f, 1062f / 1125f) // Landscape };
We can use the same technique for any Android phone and simply add it to the SimDevice list in the same way. This allows us to add an unlimited number of virtual test devices within the Editor.
Using these normalized coordinates, we can extend the GetSafeArea() method to include simulated devices when in Editor mode only. This multiplies out the normalized safe area by the runtime screen width and height, so that it will reactively work with any screen pixel size and aspect ratio we are running in the Editor’s Game Window.
Rect GetSafeArea () { Rect safeArea = Screen.safeArea; if (Application.isEditor && Sim != SimDevice.None) { Rect nsa = new Rect (0, 0, Screen.width, Screen.height); switch (Sim) { case SimDevice.iPhoneX: if (Screen.height > Screen.width) // Portrait nsa = NSA_iPhoneX[0]; else // Landscape nsa = NSA_iPhoneX[1]; break; default: break; } safeArea = new Rect (Screen.width * nsa.x, Screen.height * nsa.y, Screen.width * nsa.width, Screen.height * nsa.height); } return safeArea; }
To toggle between these sim devices at runtime, we can create a toggle script with a customizable hotkey. Attach this script to an object in any scene to enable the behavior. In any non-Editor build environment, it will destroy itself.
using UnityEngine; using System; public class SafeAreaDemo : MonoBehaviour { [SerializeField] KeyCode KeySafeArea = KeyCode.A; SafeArea.SimDevice[] Sims; int SimIdx; void Awake () { if (!Application.isEditor) Destroy (gameObject); Sims = (SafeArea.SimDevice[])Enum.GetValues (typeof (SafeArea.SimDevice)); } void Update () { if (Input.GetKeyDown (KeySafeArea)) ToggleSafeArea (); } /// <summary> /// Toggle the safe area simulation device. /// </summary> void ToggleSafeArea () { SimIdx++; if (SimIdx >= Sims.Length) SimIdx = 0; SafeArea.Sim = Sims[SimIdx]; Debug.LogFormat ("Switched to sim device {0} with debug key '{1}'", Sims[SimIdx], KeySafeArea); } }

[Update: Nov 2018] New iPhone X models

In Q3 2018, Apple released three new variations of the iPhone X: the iPhone Xs, Xs Max and XR. The most notable changes were the inclusion of the new A12 Bionic processor and different screen sizes.
Regarding their full screen aspect ratios, the iPhone X, Xs, Xs Max and XR all have a roughly identical aspect ratio of 2.165:1. To be exact, there is actually a 0.001 variance due to differences in exact screen pixel sizes. However, for the purpose of simplicity, we approximate this to 19.5:9, so that we are not overzealous with creating too many aspect ratios in the Game Window.
Regarding their safe areas, the iPhone X and Xs are identical, whereas the iPhone Xs Max and XR have a very slightly larger safe area (less than 1% difference). For completeness of testing, this safe area has been added to the Unity package as a simulation device (linked at the end of the article).

[Update: Aug 2019] Android 9.0 notch support

In Dec 2018, Unity 2018.3.0 added support for notched devices running Android 9.0 and above. Unfortunately, it contained several bugs, one of which rendered the safe area upside down. It is recommended to use 2018.4.1+ or 2019.1.2+, which include several important bug fixes to the screen safe code.
Note that to use the full safe area on Android, the following setting must be checked: Edit/Project Settings/Player - Android tab - Resolution and Presentation/Render outside safe area = true. By default, an upgraded project created before this setting existed will not have this setting checked. If set to false, your app will render the cutout as a black bar.
Android Studio now comes with an AVD for the Google Pixel 3 XL, which is the first Google-made smartphone to feature the notch. It is recommended to create an AVD using API 28 for best results.
The Unity package has been updated with an additional SimDevice for the Google Pixel 3 XL. The aspect ratio for the Pixel 3 XL is 9:18.5 in portrait and 18.5:9 in landscape. Similar to the iPhone X, there is no Portrait Upside Down mode due to the notch. Note that the safe screen area on the Google Pixel 3 XL differs from the iPhone X in one major way - the safe area only covers the notch. This means that:
  1. In portrait, there is no safe area on the side opposite the notch.
  2. In landscape, the safe area is NOT symmetrical (it only covers the side where the notch is).

[Update: Sep 2019] Official Device Simulator coming to the editor in Unity 2019.3

Unity is adding an official feature to the editor in Unity 2019.3 called the "Device Simulator". It looks like it has taken some inspiration from my Asset Store package, which is an honor. You can read more about it here:

[Update: Jan 2020] iPhone 11 release

On 20 Sep 2019, the iPhone 11 was released. There are three versions - the iPhone 11, iPhone 11 Pro and iPhone 11 Pro Max - with differences in physical size and pixel resolution.
As it turns out, these use the same safe areas as the previous iPhone X generation, so no new SimDevices are required. The iPhone 11 & iPhone 11 Pro Max have a safe area equivalent to the iPhone Xs Max; the iPhone 11 Pro has a safe area equivalent to the iPhone X.


In this article, we have created a generic way to conform to mobile safe areas on multiple devices and orientations. In addition, we have an extensible system to test and iterate quickly within the Editor using device simulation.
The scripts and test scene used here are available free for download on the Unity Asset Store.
To see Oopstacles in all its iPhone X reactive glory, visit our Facebook page for a download link, and please throw us a LIKE while you are there ;)
Thanks for reading.
Crystal Pug
9 days ago
Great article! Just think it would be tricky to do this adaptation on devices under Android 9.
Tony Joseph
3 months ago
Thanks for this tutorial. I have a small issue regarding my bg, which is a 2d sprite. How do I position it inside the safe area? Can you please help me?
Matthew Ota
5 months ago
José Ferreira MachadoGreat article, this helps me immensely! However, just a small note, on the [Update: Aug 2019] you talk about a setting under "Edit/Project Settings - Android tab - Resolution and Presentation/Render", but it's actually in Player Settings, not Project Settings. You might want to correct that, because it took me a while to find it out myself ;)
Thank you Jose, I will update the article!
Great article, this helps me immensely! However, just a small note, on the [Update: Aug 2019] you talk about a setting under "Edit/Project Settings - Android tab - Resolution and Presentation/Render", but it's actually in Player Settings, not Project Settings. You might want to correct that, because it took me a while to find it out myself ;)
Matthew Ota
6 months ago
Aleksejs SergejevsLooks pretty neat! Since the asset is free I think it would be cool if you put it up on Github. That way people would be able to make contributions to the asset.
Thanks for the suggestion Aleksejs!