How to make mobile games and UI adapt to the IPhone notch??

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By IllustratorGuy

Essentially, I am trying to do what this person does in Unity: Unity Live Help. Apple user interface guidelines require UI to not be hidden by the notch which is why I’m trying to figure this out.

enter image description here

It might be worth reading the article because it’s hard for me to explain how he does this.
But I think the person uses Screen.safeArea (in Unity) to get the safe area of the phone screen, which returns a (x, y, width, height). He converts these dimensions to “normalized anchor coordinates”. As a result, it pushes the GUI away from the edges of the screen to be in the safe area.

Just like how Unity has Screen.safeArea , Godot has a basically identical OS method called get_window_safe_area. They both return a (x, y, width, height) of the safe area’s bounds.

How can I take these width/height dimensions of the safe area and turn it into the dimensions of the GUI? So that the GUI is pushed into the safe area.

Please anybody answer. Especially for Android version. Need this too for a long time.

Amuh | 2021-04-12 15:19

:bust_in_silhouette: Reply From: dpensky

I’m also having problems with this. Did any solution come up?

:bust_in_silhouette: Reply From: DavidMag

Basically you can just wrap all your UI with a MarginContainer with a script for calculating the needed margins. So your node hierarchy would be something like this:

The script could look something like this, but big disclaimer I’ve not tested this script and it’s for Godot 4 but gives you something to work with.

UPDATE: Made minor fixes to the script after testing and checks out nicely

class_name SafeMarginContainer
extends MarginContainer

func _ready() -> void:
	var safe_area: Rect2i = DisplayServer.get_display_safe_area()
	var window_size: Vector2i = DisplayServer.window_get_real_size()

	# BASE MARGINS
	var top: int = 8
	var left: int = 8
	var bottom: int = 8
	var right: int = 8

	if window_size.x >= safe_area.size.x and window_size.y >= safe_area.size.y:
		var x_factor: float = size.x / window_size.x
		var y_factor: float = size.y / window_size.y
	
		top = max(top, safe_area.position.y * y_factor)
		left = max(left, safe_area.position.x * x_factor)
		bottom = max(bottom, abs(safe_area.end.y - window_size.y) * y_factor)
		right = max(right, abs(safe_area.end.x - window_size.x) * x_factor)

	add_theme_constant_override("margin_top", top)
	add_theme_constant_override("margin_left", left)
	add_theme_constant_override("margin_bottom", bottom)
	add_theme_constant_override("margin_right", right)

Hope it helps and happy coding! :smiley:

@DavidMag I am getting error that DisplayServer isn’t declared in the current scope?

Vickylance | 2022-10-08 08:00

Here is a version that should work with Godot 3.5

extends MarginContainer
func _ready() -> void:
var safe_area:Rect2 = OS.get_window_safe_area()
var window_size: Vector2 = get_viewport().size

# BASE MARGINS
var top: int = get("custom_constants/margin_top")
var left: int = get("custom_constants/margin_left")
var bottom: int = get("custom_constants/margin_bottom")
var right: int = get("custom_constants/margin_right")

if window_size.x >= safe_area.size.x and window_size.y >= safe_area.size.y:
	var x_factor: float = safe_area.size.x / window_size.x
	var y_factor: float = safe_area.size.y / window_size.y

	top = max(top, safe_area.position.y * y_factor)
	left = max(left, safe_area.position.x * x_factor)
	bottom = max(bottom, abs(safe_area.end.y - window_size.y) * y_factor)
	right = max(right, abs(safe_area.end.x - window_size.x) * x_factor)

set("custom_constants/margin_top", top)
set("custom_constants/margin_left", left)
set("custom_constants/margin_bottom", bottom)
set("custom_constants/margin_right", right)

Attach to MarginContainer and make sure to set Theme Overrides/Constants (or replace the get(…)-Methods in the #BASE MARGINS section by default values).

mr_holunder | 2023-02-14 20:27

This code does not really fix the notch issue, it just pushes the windows to the bottom which causes items on the bottom to vanish. Also not functional if you want to adapt for the notch and ‘home indicator’ on iOS.
a better solution would be :
1: to make the screen smaller (top and/or bottom) and with that also the width to keep ratio
2: to make the screen smaller (top and/or bottom) and position the items lower/higher depending on their position (this is how unity does it)

I read a lot of documents and forums, but I never saw such solutions.

Edit: fixed the issue by using Panels.
In my case I used 5 panels which I placed across the screen. Top, subtop,center,subbottom and bottom, each containing the items that I want for that location of the screen. Then I calculatie what the correction should be from top (with safe area) and then I reposition at start of the scene the first top or first 2 toppanels. Maybe even the first 3 top panels.
Fixed my issue completely and Im in control of the correct placements.