Device/Screen rotation event?

I want to calculate and cache some variables after a rotation event has occurred. I don’t see that in the Unity API. How?

if ((Input.deviceOrientation == DeviceOrientation.LandscapeLeft)  (Screen.orientation != ScreenOrientation.LandscapeLeft))
{
	Screen.orientation = ScreenOrientation.LandscapeLeft;
}
		
if ((Input.deviceOrientation == DeviceOrientation.LandscapeRight)  (Screen.orientation != ScreenOrientation.LandscapeRight))
{
	Screen.orientation = ScreenOrientation.LandscapeRight;
}

This stuff?

Could you check if the screen orientation is not equal to the previous frames orientation. Then fire the event if true.

I’m looking for an event, not a constant Update check. (Unity typically just gives us MonoBehaviour methods with “On” in front of them.) I don’t need it to be fully contained in the Unity API if there’s a better way of handling it.

I guess it’s possible via xcode event (didRotateBlah). This could get sent via UnitySendMessage from objective C to unity to a gameObject, in the same manner as the “On” functions. That is the only workaround I know, seems long-winded.

As it turns out, the enumerator list constants for ScreenOrientation and DeviceOrientation match, so I’m going with this.

IEnumerator CheckForChange() {
	while (true)
		switch (Input.deviceOrientation) {
			case DeviceOrientation.Unknown: 
			case DeviceOrientation.FaceUp: 
			case DeviceOrientation.FaceDown:
				yield return null;
				break;
			default:
				yield return Screen.orientation == (ScreenOrientation)Input.deviceOrientation ?
					null : StartCoroutine(Fade());
				break;
	    }
}

This thread is old, but is there some new solution for checking change orientation? Or I have to do it in Update etc?

1 Like

I think best solution - is used native code at Android/iOS and call callback to Unity.

I’ve been researching this lately, and came up with the following class.
Warning: Compiles, but untested!
Just add the DeviceChange script to any active GameObject.
I stole a bit of code from places (thanks Jessy!).

You subscribe to the change events, and can have multiple methods subscribed to receive the event notice.
For example, you could have each of your UI classes get notified when the resolution or orientation changes like this:

DeviceChange.OnOrientationChange += MyOrientationChangeCode;
DeviceChange.OnResolutionChange += MyResolutionChangeCode;
DeviceChange.OnResolutionChange += MyOtherResolutionChangeCode;

void MyOrientationChangeCode(DeviceOrientation orientation) {
}

void MyResolutionChangeCode(Vector2 resolution) {
}

Device Change Class:

using System;
using System.Collections;
using UnityEngine;

public class DeviceChange : MonoBehaviour {
    public static event Action<Vector2> OnResolutionChange;
    public static event Action<DeviceOrientation> OnOrientationChange;
    public static float CheckDelay = 0.5f;        // How long to wait until we check again.

    static Vector2 resolution;                    // Current Resolution
    static DeviceOrientation orientation;        // Current Device Orientation
    static bool isAlive = true;                    // Keep this script running?

    void Start() {
        StartCoroutine(CheckForChange());
    }

    IEnumerator CheckForChange(){
        resolution = new Vector2(Screen.width, Screen.height);
        orientation = Input.deviceOrientation;

        while (isAlive) {

            // Check for a Resolution Change
            if (resolution.x != Screen.width || resolution.y != Screen.height ) {
                resolution = new Vector2(Screen.width, Screen.height);
                if (OnResolutionChange != null) OnResolutionChange(resolution);
            }

            // Check for an Orientation Change
            switch (Input.deviceOrientation) {
                case DeviceOrientation.Unknown:            // Ignore
                case DeviceOrientation.FaceUp:            // Ignore
                case DeviceOrientation.FaceDown:        // Ignore
                    break;
                default:
                    if (orientation != Input.deviceOrientation) {
                        orientation = Input.deviceOrientation;
                        if (OnOrientationChange != null) OnOrientationChange(orientation);
                    }
                    break;
            }

            yield return new WaitForSeconds(CheckDelay);
        }
    }

    void OnDestroy(){
        isAlive = false;
    }

}

[Edit] Simplified code by using Actions, not Delegates.
[Edit 2] Fixed bug (removed unneeded parenthesis) in example code

20 Likes

Your Device Change Class works great, thank you!

Indeed it does. Thank you from me, too!

It’s incredible there is no notification from Unity for this. It’s hard to believe.

9 Likes

When would the resolution change on a mobile device?

See Redirecting to latest version of com.unity.ugui

If you have a script attached to a RectTransform, when the dimensions of that rect transform changes (e.g. as a result of a rotation), then that callback is called.

6 Likes

Oh wow - thanks @Mohamed-Mortada

OnRectTransformDimensionsChange … magic

Is that new?

2 Likes

If you created a top-level gameobject (a panel perhaps) with a RectTransform anchor set to Stretch-Stretch to cover the entire screen, then I suppose you can watch for resolution changes by using OnRectTransformDimensionsChange() on that object. That would be neat to see.

Thank you so much!

This might seem a stupid change on top of Doug’s version, but I think using the “editor-ready” UnityEvents is nice.

Here it is, but I take no credit since it’s a really really small improvement (IMHO):

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Events;

public class DeviceChange : MonoBehaviour
{
    public UnityEvent OnResolutionChange = new UnityEvent();
    public UnityEvent OnOrientationChange = new UnityEvent();
    public static float CheckDelay = 0.5f;        // How long to wait until we check again.

    public static Vector2 resolution;                    // Current Resolution
    public static DeviceOrientation orientation;        // Current Device Orientation
    static bool isAlive = true;                    // Keep this script running?

    void Start()
    {
        StartCoroutine(CheckForChange());
    }

    IEnumerator CheckForChange()
    {
        resolution = new Vector2(Screen.width, Screen.height);
        orientation = Input.deviceOrientation;

        while (isAlive)
        {

            // Check for a Resolution Change
            if (resolution.x != Screen.width || resolution.y != Screen.height)
            {
                resolution = new Vector2(Screen.width, Screen.height);
                OnResolutionChange.Invoke();
            }

            // Check for an Orientation Change
            switch (Input.deviceOrientation)
            {
                case DeviceOrientation.Unknown:            // Ignore
                case DeviceOrientation.FaceUp:            // Ignore
                case DeviceOrientation.FaceDown:        // Ignore
                    break;
                default:
                    if (orientation != Input.deviceOrientation)
                    {
                        orientation = Input.deviceOrientation;
                        OnOrientationChange.Invoke();
                    }
                    break;
            }

            yield return new WaitForSeconds(CheckDelay);
        }
    }

    void OnDestroy()
    {
        isAlive = false;
    }

}
2 Likes

@DougMcFarlane @tfHandle

Thanks It was desired to simply change the Ortho size with orientation. The script was useful as was and tfHandle helped make it easier. Simply adding the script to the object you want changed and making the var for it instead of the cam used in my example included…

3291902–254951–DeviceOrientationChange.cs (2 KB)

I’ve made what I think to be an improvement so it doesn’t have to do a constant check and makes the call on the frame it occurs (instead of waiting for the CheckDelay), it utilizes Unity’s OnRectTransformDimensionsChange call. I made use of the lazy singleton pattern. I also improved the resolution change check slightly so it won’t callback when the screen is rotated 90 degrees.

using UnityEngine;
using UnityEngine.Events;

[RequireComponent(typeof(RectTransform))]
public class ScreenWatcher : MonoBehaviour
{
    static ScreenWatcher instance = null;
    static UnityEvent OnResolutionChange = new UnityEvent();
    static UnityEvent OnOrientationChange = new UnityEvent();
    static Vector2 resolution; // Current Resolution
    static ScreenOrientation orientation; // Current Screen Orientation

    static void init()
    {
        if (instance != null) return;

        resolution = new Vector2(Screen.width, Screen.height);
        orientation = Screen.orientation;

        GameObject canvas = new GameObject("ScreenWatcher");
        canvas.AddComponent<Canvas>().renderMode = RenderMode.ScreenSpaceOverlay;
        instance = canvas.AddComponent<ScreenWatcher>();
        DontDestroyOnLoad(canvas);
    }


    private void Awake()
    {
        if (instance != this)
        {
            Destroy(this);
        }
    }

    private void OnRectTransformDimensionsChange()
    {
        // Check for an Orientation Change
        ScreenOrientation curOri = Screen.orientation;
        switch (curOri)
        {
            case ScreenOrientation.Unknown: // Ignore
            {
                break;
            }
            default:
            {
                if (orientation != curOri)
                {
                    orientation = curOri;
                    OnOrientationChange.Invoke();
                }
                break;
            }
        }

        // Check for a Resolution Change
        if ((resolution.x != Screen.width && resolution.x != Screen.height) || (resolution.y != Screen.height && resolution.y != Screen.width))
        {
            resolution = new Vector2(Screen.width, Screen.height);
            OnResolutionChange.Invoke();
        }
    }

    public static void AddResolutionChangeListener(UnityAction callback)
    {
        init();
        OnResolutionChange.AddListener(callback);
    }

    public static void RemoveResolutionChangeListener(UnityAction callback)
    {
        OnResolutionChange.RemoveListener(callback);
    }

    public static void AddOrientationChangeListener(UnityAction callback)
    {
        init();
        OnOrientationChange.AddListener(callback);
    }

    public static void RemoveOrientationChangeListener(UnityAction callback)
    {
        OnOrientationChange.RemoveListener(callback);
    }

    private void OnDestroy()
    {
        OnResolutionChange.RemoveAllListeners();
        OnOrientationChange.RemoveAllListeners();
        if (instance == this)
        {
            instance = null;
        }
    }
}