Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Issues with UI safe area on Galaxy S10?

Discussion in 'Android' started by magglemitch, Feb 16, 2020.

  1. magglemitch

    magglemitch

    Joined:
    Dec 8, 2013
    Posts:
    110
    I've been using the below Safe Area script to control UI panels to make sure they can adjust to account for the various notches and weird things in today's phones. Generally, this script has been awesome and has worked perfectly.

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.UI;
    6. using UnityEngine.Events;
    7. [RequireComponent(typeof(Canvas))]
    8. public class CanvasHelper : MonoBehaviour
    9. {
    10.    public static UnityEvent onOrientationChange = new UnityEvent();
    11.    public static UnityEvent onResolutionChange = new UnityEvent();
    12.    public static bool isLandscape { get; private set; }
    13.  
    14.    private static List<CanvasHelper> helpers = new List<CanvasHelper>();
    15.  
    16.    private static bool screenChangeVarsInitialized = false;
    17.    private static ScreenOrientation lastOrientation = ScreenOrientation.Unknown;
    18.    private static Vector2 lastResolution = Vector2.zero;
    19.    private static Vector2 lastSafeArea = Vector2.zero;
    20.  
    21.     private static Vector2 wantedReferenceResolution;
    22.    private static Camera wantedCanvasCamera;
    23.  
    24.    private Canvas canvas;
    25.    private CanvasScaler scaler;
    26.    private RectTransform rectTransform;
    27.  
    28.    public RectTransform safeAreaTransform;
    29.  
    30.    void Awake()
    31.    {
    32.        if(!helpers.Contains(this))
    33.            helpers.Add(this);
    34.      
    35.        canvas = GetComponent<Canvas>();
    36.        scaler = GetComponent<CanvasScaler>();
    37.        rectTransform = GetComponent<RectTransform>();
    38.         wantedReferenceResolution = scaler.referenceResolution;
    39.        UpdateReferenceResolution();
    40.        UpdateCanvasCamera();
    41.      
    42.         if (safeAreaTransform == null)
    43.         {
    44.             safeAreaTransform = transform.GetChild(0).GetComponent<RectTransform>();
    45.         }
    46.         //safeAreaTransform = transform.Find("SafeArea") as RectTransform;
    47.  
    48.         if (!screenChangeVarsInitialized)
    49.        {
    50.            lastOrientation = Screen.orientation;
    51.            lastResolution.x = Screen.width;
    52.            lastResolution.y = Screen.height;
    53.            lastSafeArea = Screen.safeArea.size;
    54.      
    55.            screenChangeVarsInitialized = true;
    56.        }
    57.    }
    58.  
    59.    void Start()
    60.    {
    61.        ApplySafeArea();
    62.        // safeAreaTransform.gameObject.SetActive(false);
    63.       //  Invoke("turnbackOn", 0.1f);
    64.    }
    65.  
    66.     void turnbackOn()
    67.     {
    68.         safeAreaTransform.gameObject.SetActive(true);
    69.     }
    70.  
    71.    void Update()
    72.    {
    73.        if(helpers[0] != this)
    74.            return;
    75.          
    76.        if(Application.isMobilePlatform)
    77.        {
    78.            if(Screen.orientation != lastOrientation)
    79.                OrientationChanged();
    80.          
    81.            if(Screen.safeArea.size != lastSafeArea)
    82.                SafeAreaChanged();
    83.        }
    84.        else
    85.        {
    86.            //resolution of mobile devices should stay the same always, right?
    87.            // so this check should only happen everywhere else
    88.            if(Screen.width != lastResolution.x || Screen.height != lastResolution.y)
    89.                ResolutionChanged();
    90.        }
    91.    }
    92.  
    93.    void ApplySafeArea()
    94.    {
    95.        if(safeAreaTransform == null)
    96.            return;
    97.      
    98.        var safeArea = Screen.safeArea;
    99.      
    100.        var anchorMin = safeArea.position;
    101.        var anchorMax = safeArea.position + safeArea.size;
    102.        anchorMin.x /= canvas.pixelRect.width;
    103.        anchorMin.y /= canvas.pixelRect.height;
    104.        anchorMax.x /= canvas.pixelRect.width;
    105.        anchorMax.y /= canvas.pixelRect.height;
    106.      
    107.        safeAreaTransform.anchorMin = anchorMin;
    108.        safeAreaTransform.anchorMax = anchorMax;
    109.      
    110.        //Debug.Log(
    111.        //    "ApplySafeArea:" +
    112.        //    "\n Screen.orientation: " + Screen.orientation +
    113.        //    #if UNITY_IOS
    114.        //    "\n Device.generation: " + UnityEngine.iOS.Device.generation.ToString() +
    115.        //    #endif
    116.        //    "\n Screen.safeArea.position: " + Screen.safeArea.position.ToString() +
    117.        //    "\n Screen.safeArea.size: " + Screen.safeArea.size.ToString() +
    118.        //    "\n Screen.width / height: (" + Screen.width.ToString() + ", " + Screen.height.ToString() + ")" +
    119.        //    "\n canvas.pixelRect.size: " + canvas.pixelRect.size.ToString() +
    120.        //    "\n anchorMin: " + anchorMin.ToString() +
    121.        //    "\n anchorMax: " + anchorMax.ToString());
    122.    }
    123.  
    124.    void UpdateCanvasCamera()
    125.    {
    126.        if(canvas.worldCamera == null && wantedCanvasCamera != null)
    127.            canvas.worldCamera = wantedCanvasCamera;
    128.    }
    129.  
    130.    void UpdateReferenceResolution()
    131.    {
    132.        if(scaler.referenceResolution != wantedReferenceResolution)
    133.            scaler.referenceResolution = wantedReferenceResolution;
    134.    }
    135.  
    136.    void OnDestroy()
    137.    {
    138.        if(helpers != null && helpers.Contains(this))
    139.            helpers.Remove(this);
    140.    }
    141.  
    142.    private static void OrientationChanged()
    143.    {
    144.        //Debug.Log("Orientation changed from " + lastOrientation + " to " + Screen.orientation + " at " + Time.time);
    145.      
    146.        lastOrientation = Screen.orientation;
    147.        lastResolution.x = Screen.width;
    148.        lastResolution.y = Screen.height;
    149.      
    150.        isLandscape = lastOrientation == ScreenOrientation.LandscapeLeft || lastOrientation == ScreenOrientation.LandscapeRight || lastOrientation == ScreenOrientation.Landscape;
    151.        onOrientationChange.Invoke();
    152.      
    153.    }
    154.  
    155.    private static void ResolutionChanged()
    156.    {
    157.        if(lastResolution.x == Screen.width && lastResolution.y == Screen.height)
    158.            return;
    159.      
    160.        //Debug.Log("Resolution changed from " + lastResolution + " to (" + Screen.width + ", " + Screen.height + ") at " + Time.time);
    161.      
    162.        lastResolution.x = Screen.width;
    163.        lastResolution.y = Screen.height;
    164.      
    165.        isLandscape = Screen.width > Screen.height;
    166.        onResolutionChange.Invoke();
    167.    }
    168.  
    169.    private static void SafeAreaChanged()
    170.    {
    171.        if(lastSafeArea == Screen.safeArea.size)
    172.            return;
    173.      
    174.        //Debug.Log("Safe Area changed from " + lastSafeArea + " to " + Screen.safeArea.size + " at " + Time.time);
    175.      
    176.        lastSafeArea = Screen.safeArea.size;
    177.      
    178.        for (int i = 0; i < helpers.Count; i++)
    179.        {
    180.            helpers[i].ApplySafeArea();
    181.        }
    182.    }
    183.  
    184.    public static void SetAllCanvasCamera(Camera cam)
    185.    {
    186.        if(wantedCanvasCamera == cam)
    187.            return;
    188.      
    189.        wantedCanvasCamera = cam;
    190.      
    191.        for (int i = 0; i < helpers.Count; i++)
    192.        {
    193.            helpers[i].UpdateCanvasCamera();
    194.        }
    195.    }
    196.  
    197.    public static void SetAllReferenceResolutions(Vector2 newReferenceResolution)
    198.    {
    199.        if(wantedReferenceResolution == newReferenceResolution)
    200.            return;
    201.          
    202.        //Debug.Log("Reference resolution changed from " + wantedReferenceResolution + " to " + newReferenceResolution + " at " + Time.time);
    203.      
    204.        wantedReferenceResolution = newReferenceResolution;
    205.      
    206.        for (int i = 0; i < helpers.Count; i++)
    207.        {
    208.            helpers[i].UpdateReferenceResolution();
    209.        }
    210.    }
    211.  
    212.    public static Vector2 CanvasSize()
    213.    {
    214.        return helpers[0].rectTransform.sizeDelta;
    215.    }
    216.  
    217.    public static Vector2 SafeAreaSize()
    218.    {
    219.        for (int i = 0; i < helpers.Count; i++)
    220.        {
    221.            if(helpers[i].safeAreaTransform != null)
    222.            {
    223.                return helpers[i].safeAreaTransform.sizeDelta;
    224.            }
    225.        }
    226.      
    227.        return CanvasSize();
    228.    }
    229.  
    230.    public static Vector2 GetReferenceResolution()
    231.    {
    232.        return wantedReferenceResolution;
    233.    }
    234.  
    235.  
    236. }


    Have noticed it playing up a lot on my Samsung Galaxy S10 - occasionally the canvas would just be missing completely from view. It probably works about 50 percent of the time.

    I don't think there is anything crazy in my settings making it mess up - I have reverted player settings back to default for testing and this issue still happens.

    Am using Unity 2019.3.0f6
     
    Last edited: Feb 16, 2020
  2. rjonaitis

    rjonaitis

    Unity Technologies

    Joined:
    Jan 5, 2017
    Posts:
    115
    Try adding a check if Screen.safeArea values are valid (width, height are not NaN and not equal to 0). There was a possibility for such values, it is fixed and will be backported to 2019.3 later on.