Search Unity

  1. Unity 2018.3 is now released.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. We've updated our Terms of Service. Please read our blog post from Unity CTO and Co-Founder Joachim Ante here
    Dismiss Notice
  4. Want to provide direct feedback to the Unity team? Join the Unity Advisory Panel.
    Dismiss Notice
  5. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice

Device/Screen rotation event?

Discussion in 'iOS and tvOS' started by Jessy, Jan 8, 2012.

  1. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,327
    I want to calculate and cache some variables after a rotation event has occurred. I don't see that in the Unity API. How?
     
  2. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    24,195
    Code (csharp):
    1. if ((Input.deviceOrientation == DeviceOrientation.LandscapeLeft)  (Screen.orientation != ScreenOrientation.LandscapeLeft))
    2. {
    3.     Screen.orientation = ScreenOrientation.LandscapeLeft;
    4. }
    5.        
    6. if ((Input.deviceOrientation == DeviceOrientation.LandscapeRight)  (Screen.orientation != ScreenOrientation.LandscapeRight))
    7. {
    8.     Screen.orientation = ScreenOrientation.LandscapeRight;
    9. }
    10.  
    This stuff?
     
  3. _Daniel_

    _Daniel_

    Joined:
    Feb 28, 2007
    Posts:
    2,632
    Could you check if the screen orientation is not equal to the previous frames orientation. Then fire the event if true.
     
  4. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,327
    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.
     
    Last edited: Jan 8, 2012
  5. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    24,195
    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.
     
  6. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,327
    As it turns out, the enumerator list constants for ScreenOrientation and DeviceOrientation match, so I'm going with this.

    Code (csharp):
    1. IEnumerator CheckForChange() {
    2.     while (true)
    3.         switch (Input.deviceOrientation) {
    4.             case DeviceOrientation.Unknown:
    5.             case DeviceOrientation.FaceUp:
    6.             case DeviceOrientation.FaceDown:
    7.                 yield return null;
    8.                 break;
    9.             default:
    10.                 yield return Screen.orientation == (ScreenOrientation)Input.deviceOrientation ?
    11.                     null : StartCoroutine(Fade());
    12.                 break;
    13.         }
    14. }
     
    Last edited: Jan 11, 2012
  7. Cenda

    Cenda

    Joined:
    Jun 3, 2010
    Posts:
    50
    This thread is old, but is there some new solution for checking change orientation? Or I have to do it in Update etc?
     
  8. el_santo

    el_santo

    Joined:
    Feb 27, 2015
    Posts:
    3
    I think best solution - is used native code at Android/iOS and call callback to Unity.
     
  9. DougMcFarlane

    DougMcFarlane

    Joined:
    Apr 25, 2009
    Posts:
    197
    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:
    Code (CSharp):
    1. DeviceChange.OnOrientationChange += MyOrientationChangeCode;
    2. DeviceChange.OnResolutionChange += MyResolutionChangeCode;
    3. DeviceChange.OnResolutionChange += MyOtherResolutionChangeCode;
    4.  
    5. void MyOrientationChangeCode(DeviceOrientation orientation) {
    6. }
    7.  
    8. void MyResolutionChangeCode(Vector2 resolution) {
    9. }
    Device Change Class:
    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using UnityEngine;
    4.  
    5. public class DeviceChange : MonoBehaviour {
    6.     public static event Action<Vector2> OnResolutionChange;
    7.     public static event Action<DeviceOrientation> OnOrientationChange;
    8.     public static float CheckDelay = 0.5f;        // How long to wait until we check again.
    9.  
    10.     static Vector2 resolution;                    // Current Resolution
    11.     static DeviceOrientation orientation;        // Current Device Orientation
    12.     static bool isAlive = true;                    // Keep this script running?
    13.  
    14.     void Start() {
    15.         StartCoroutine(CheckForChange());
    16.     }
    17.  
    18.     IEnumerator CheckForChange(){
    19.         resolution = new Vector2(Screen.width, Screen.height);
    20.         orientation = Input.deviceOrientation;
    21.  
    22.         while (isAlive) {
    23.  
    24.             // Check for a Resolution Change
    25.             if (resolution.x != Screen.width || resolution.y != Screen.height ) {
    26.                 resolution = new Vector2(Screen.width, Screen.height);
    27.                 if (OnResolutionChange != null) OnResolutionChange(resolution);
    28.             }
    29.  
    30.             // Check for an Orientation Change
    31.             switch (Input.deviceOrientation) {
    32.                 case DeviceOrientation.Unknown:            // Ignore
    33.                 case DeviceOrientation.FaceUp:            // Ignore
    34.                 case DeviceOrientation.FaceDown:        // Ignore
    35.                     break;
    36.                 default:
    37.                     if (orientation != Input.deviceOrientation) {
    38.                         orientation = Input.deviceOrientation;
    39.                         if (OnOrientationChange != null) OnOrientationChange(orientation);
    40.                     }
    41.                     break;
    42.             }
    43.  
    44.             yield return new WaitForSeconds(CheckDelay);
    45.         }
    46.     }
    47.  
    48.     void OnDestroy(){
    49.         isAlive = false;
    50.     }
    51.  
    52. }
    [Edit] Simplified code by using Actions, not Delegates.
    [Edit 2] Fixed bug (removed unneeded parenthesis) in example code
     
    Last edited: Oct 14, 2015
  10. JEDressler

    JEDressler

    Joined:
    Apr 18, 2015
    Posts:
    7
    Your Device Change Class works great, thank you!
     
  11. pea

    pea

    Joined:
    Oct 29, 2013
    Posts:
    98
    Indeed it does. Thank you from me, too!
     
  12. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    397
    It's incredible there is no notification from Unity for this. It's hard to believe.
     
    zoooom and aimozs like this.
  13. supertonkers

    supertonkers

    Joined:
    Jun 13, 2015
    Posts:
    4
    When would the resolution change on a mobile device?
     
  14. UnityDev291

    UnityDev291

    Joined:
    Jul 21, 2014
    Posts:
    8
    misher, Mohamed-Mortada and pea like this.
  15. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    397
  16. DougMcFarlane

    DougMcFarlane

    Joined:
    Apr 25, 2009
    Posts:
    197
    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.
     
  17. tiny-ant

    tiny-ant

    Joined:
    Feb 6, 2013
    Posts:
    1
    Thank you so much!
     
  18. tfHandle

    tfHandle

    Joined:
    Nov 10, 2017
    Posts:
    1
    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):

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using UnityEngine;
    4. using UnityEngine.Events;
    5.  
    6. public class DeviceChange : MonoBehaviour
    7. {
    8.     public UnityEvent OnResolutionChange = new UnityEvent();
    9.     public UnityEvent OnOrientationChange = new UnityEvent();
    10.     public static float CheckDelay = 0.5f;        // How long to wait until we check again.
    11.  
    12.     public static Vector2 resolution;                    // Current Resolution
    13.     public static DeviceOrientation orientation;        // Current Device Orientation
    14.     static bool isAlive = true;                    // Keep this script running?
    15.  
    16.     void Start()
    17.     {
    18.         StartCoroutine(CheckForChange());
    19.     }
    20.  
    21.     IEnumerator CheckForChange()
    22.     {
    23.         resolution = new Vector2(Screen.width, Screen.height);
    24.         orientation = Input.deviceOrientation;
    25.  
    26.         while (isAlive)
    27.         {
    28.  
    29.             // Check for a Resolution Change
    30.             if (resolution.x != Screen.width || resolution.y != Screen.height)
    31.             {
    32.                 resolution = new Vector2(Screen.width, Screen.height);
    33.                 OnResolutionChange.Invoke();
    34.             }
    35.  
    36.             // Check for an Orientation Change
    37.             switch (Input.deviceOrientation)
    38.             {
    39.                 case DeviceOrientation.Unknown:            // Ignore
    40.                 case DeviceOrientation.FaceUp:            // Ignore
    41.                 case DeviceOrientation.FaceDown:        // Ignore
    42.                     break;
    43.                 default:
    44.                     if (orientation != Input.deviceOrientation)
    45.                     {
    46.                         orientation = Input.deviceOrientation;
    47.                         OnOrientationChange.Invoke();
    48.                     }
    49.                     break;
    50.             }
    51.  
    52.             yield return new WaitForSeconds(CheckDelay);
    53.         }
    54.     }
    55.  
    56.     void OnDestroy()
    57.     {
    58.         isAlive = false;
    59.     }
    60.  
    61. }
     
    CrandellWS likes this.
  19. CrandellWS

    CrandellWS

    Joined:
    Oct 31, 2015
    Posts:
    75
    @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...
     

    Attached Files:

  20. ProtoTerminator

    ProtoTerminator

    Joined:
    Nov 19, 2013
    Posts:
    13
    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.


    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.Events;
    4.  
    5. [RequireComponent(typeof(RectTransform))]
    6. public class ScreenWatcher : MonoBehaviour
    7. {
    8.     static ScreenWatcher instance = null;
    9.     static UnityEvent OnResolutionChange = new UnityEvent();
    10.     static UnityEvent OnOrientationChange = new UnityEvent();
    11.     static Vector2 resolution; // Current Resolution
    12.     static ScreenOrientation orientation; // Current Screen Orientation
    13.  
    14.     static void init()
    15.     {
    16.         if (instance != null) return;
    17.  
    18.         resolution = new Vector2(Screen.width, Screen.height);
    19.         orientation = Screen.orientation;
    20.  
    21.         GameObject canvas = new GameObject("ScreenWatcher");
    22.         canvas.AddComponent<Canvas>().renderMode = RenderMode.ScreenSpaceOverlay;
    23.         instance = canvas.AddComponent<ScreenWatcher>();
    24.         DontDestroyOnLoad(canvas);
    25.     }
    26.  
    27.  
    28.     private void Awake()
    29.     {
    30.         if (instance != this)
    31.         {
    32.             Destroy(this);
    33.         }
    34.     }
    35.  
    36.     private void OnRectTransformDimensionsChange()
    37.     {
    38.         // Check for an Orientation Change
    39.         ScreenOrientation curOri = Screen.orientation;
    40.         switch (curOri)
    41.         {
    42.             case ScreenOrientation.Unknown: // Ignore
    43.             {
    44.                 break;
    45.             }
    46.             default:
    47.             {
    48.                 if (orientation != curOri)
    49.                 {
    50.                     orientation = curOri;
    51.                     OnOrientationChange.Invoke();
    52.                 }
    53.                 break;
    54.             }
    55.         }
    56.  
    57.         // Check for a Resolution Change
    58.         if ((resolution.x != Screen.width && resolution.x != Screen.height) || (resolution.y != Screen.height && resolution.y != Screen.width))
    59.         {
    60.             resolution = new Vector2(Screen.width, Screen.height);
    61.             OnResolutionChange.Invoke();
    62.         }
    63.     }
    64.  
    65.     public static void AddResolutionChangeListener(UnityAction callback)
    66.     {
    67.         init();
    68.         OnResolutionChange.AddListener(callback);
    69.     }
    70.  
    71.     public static void RemoveResolutionChangeListener(UnityAction callback)
    72.     {
    73.         OnResolutionChange.RemoveListener(callback);
    74.     }
    75.  
    76.     public static void AddOrientationChangeListener(UnityAction callback)
    77.     {
    78.         init();
    79.         OnOrientationChange.AddListener(callback);
    80.     }
    81.  
    82.     public static void RemoveOrientationChangeListener(UnityAction callback)
    83.     {
    84.         OnOrientationChange.RemoveListener(callback);
    85.     }
    86.  
    87.     private void OnDestroy()
    88.     {
    89.         OnResolutionChange.RemoveAllListeners();
    90.         OnOrientationChange.RemoveAllListeners();
    91.         if (instance == this)
    92.         {
    93.             instance = null;
    94.         }
    95.     }
    96. }
    97.  
     
    Last edited: Dec 14, 2017
  21. StanleyBishop

    StanleyBishop

    Joined:
    Aug 21, 2017
    Posts:
    2
    @ProtoTerminator Maybe I did something wrong, but it didn't work for me, while code posted by @tfHandle did. Built from Unity to Xcode simulator, didn't test on device.

    Code (CSharp):
    1.  
    2.     void Start ()
    3.     {
    4.         Debug.Log("Started");
    5.         ScreenWatcher.AddOrientationChangeListener (OnOrientationChange);
    6.     }
    7.  
    8.     public void OnOrientationChange ()
    9.     {
    10.         Debug.Log ("Orientation changed");
    11.     }
    12.  
     
  22. ProtoTerminator

    ProtoTerminator

    Joined:
    Nov 19, 2013
    Posts:
    13
    @StanBishop Woops, That's because Unity calls Awake() during the AddComponent before it actually gets assigned to instance, so it destroys it immediately. Change Awake() to Start() and it should be good.

    I also fixed the OnDestroy() here:


    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.Events;
    4.  
    5. [RequireComponent(typeof(RectTransform))]
    6. public class ScreenWatcher : MonoBehaviour
    7. {
    8.     static ScreenWatcher instance = null;
    9.     public static ScreenWatcher Instance { get { return instance; } }
    10.     static UnityEvent OnResolutionChange = null;
    11.     static UnityEvent OnOrientationChange = null;
    12.     static Vector2 resolution; // Current Resolution
    13.     static ScreenOrientation orientation; // Current Screen Orientation
    14.  
    15.     static void init()
    16.     {
    17.         if (instance != null) return;
    18.  
    19.         resolution = new Vector2(Screen.width, Screen.height);
    20.         orientation = Screen.orientation;
    21.  
    22.         OnResolutionChange = new UnityEvent();
    23.         OnOrientationChange = new UnityEvent();
    24.         GameObject canvas = new GameObject("ScreenWatcher");
    25.         canvas.AddComponent<Canvas>().renderMode = RenderMode.ScreenSpaceOverlay;
    26.         instance = canvas.AddComponent<ScreenWatcher>();
    27.         DontDestroyOnLoad(canvas);
    28.     }
    29.  
    30.     private void Start()
    31.     {
    32.         if (instance != this)
    33.         {
    34.             Destroy(this);
    35.         }
    36.     }
    37.  
    38.     private void OnRectTransformDimensionsChange()
    39.     {
    40.         // Check for an orientation change.
    41.         ScreenOrientation curOri = Screen.orientation;
    42.         switch (curOri)
    43.         {
    44.             case ScreenOrientation.Unknown: // Ignore
    45.             {
    46.                 break;
    47.             }
    48.             default:
    49.             {
    50.                 if (orientation != curOri)
    51.                 {
    52.                     orientation = curOri;
    53.                     OnOrientationChange.Invoke();
    54.                 }
    55.                 break;
    56.             }
    57.         }
    58.  
    59.         // Check for a resolution change.
    60.         if ((resolution.x != Screen.width && resolution.x != Screen.height) || (resolution.y != Screen.height && resolution.y != Screen.width))
    61.         {
    62.             resolution = new Vector2(Screen.width, Screen.height);
    63.             OnResolutionChange.Invoke();
    64.         }
    65.     }
    66.  
    67.     public static void AddResolutionChangeListener(UnityAction callback)
    68.     {
    69.         init();
    70.         OnResolutionChange.AddListener(callback);
    71.     }
    72.  
    73.     public static void RemoveResolutionChangeListener(UnityAction callback)
    74.     {
    75.         OnResolutionChange.RemoveListener(callback);
    76.     }
    77.  
    78.     public static void AddOrientationChangeListener(UnityAction callback)
    79.     {
    80.         init();
    81.         OnOrientationChange.AddListener(callback);
    82.     }
    83.  
    84.     public static void RemoveOrientationChangeListener(UnityAction callback)
    85.     {
    86.         OnOrientationChange.RemoveListener(callback);
    87.     }
    88.  
    89.     private void OnDestroy()
    90.     {
    91.         if (instance == this)
    92.         {
    93.             // Clean up memory.
    94.             OnResolutionChange.RemoveAllListeners();
    95.             OnResolutionChange = null;
    96.             OnOrientationChange.RemoveAllListeners();
    97.             OnOrientationChange = null;
    98.             instance = null;
    99.         }
    100.     }
    101. }
    102.  
    [EDIT] I just tested on my android, and it does not detect a change between Portrait/PortraitUpsideDown or LandscapeRight/LandscapeLeft. That's a limitation of the OnRectTransformDimensionsChange because the rect itself is still the same in that case. If you need to detect between those 180 degree rotations, I guess your best bet will be to use tfHandle's code above.
     
    Last edited: Jan 6, 2018
  23. SweatyChair

    SweatyChair

    Joined:
    Feb 15, 2016
    Posts:
    91
    My script using Screen.orientation only with less code, which works fine on mobile for detecting device orientation change.

    Code (csharp):
    1.  
    2. using System;
    3. using System.Collections;
    4. using UnityEngine;
    5. using UnityEngine.Events;
    6.  
    7. public class OrientationManager : MonoBehaviour
    8. {
    9.  
    10.     // This event will only be called when an orientation changed (i.e. won't be call at lanch)
    11.     public static event UnityAction<ScreenOrientation> orientationChangedEvent;
    12.  
    13.     [SerializeField] private bool _debugMode = false;
    14.  
    15.     private ScreenOrientation _orientation;
    16.  
    17.     void Start()
    18.     {
    19.         _orientation = Screen.orientation;
    20.         InvokeRepeating("CheckForChange", 1, 1);
    21.     }
    22.  
    23.     private static void OnOrientationChanged(ScreenOrientation orientation)
    24.     {
    25.         if (orientationChangedEvent != null)
    26.             orientationChangedEvent(orientation);
    27.     }
    28.  
    29.     private void CheckForChange()
    30.     {
    31.         if (_debugMode)
    32.             Debug.Log("Screen.orientation=" + Screen.orientation);
    33.         if (_orientation != Screen.orientation) {
    34.             _orientation = Screen.orientation;
    35.             OnOrientationChanged(_orientation);
    36.         }
    37.     }
    38.  
    39.     #if UNITY_EDITOR
    40.  
    41.     [ContextMenu("Print Orientation")]
    42.     private void PrintOrientation()
    43.     {
    44.         Debug.Log(_orientation);
    45.     }
    46.  
    47.     [ContextMenu("Simulate Landscape Left")]
    48.     private void SetLandscapeLeft()
    49.     {
    50.         OnOrientationChanged(ScreenOrientation.LandscapeLeft);
    51.     }
    52.  
    53.     [UnityEditor.MenuItem("Debug/Orientation/Simulate Landscape Left")]
    54.     private static void DoSetLandscapeLeft()
    55.     {
    56.         OnOrientationChanged(ScreenOrientation.LandscapeLeft);
    57.     }
    58.  
    59.     [ContextMenu("Simulate Landscape Right")]
    60.     private void SetLandscapeRight()
    61.     {
    62.         OnOrientationChanged(ScreenOrientation.LandscapeRight);
    63.     }
    64.  
    65.     [UnityEditor.MenuItem("Debug/Orientation/Simulate Landscape Right")]
    66.     private static void DoSetLandscapeRight()
    67.     {
    68.         OnOrientationChanged(ScreenOrientation.LandscapeRight);
    69.     }
    70.  
    71.     #endif
    72.  
    73. }
    74.  
     
    Last edited: Mar 1, 2018
  24. Jamso

    Jamso

    Joined:
    May 5, 2016
    Posts:
    10
    A question, why use INVOKE? You could use Update. The other thing, I'm trying to use your code, how do I do some action when I change direction? It happens that if I put an action (move an image) with the INVOKE, the change of position is repeated in loop until it disappears from the screen, and what I need is for it to move only when changing and not at every moment.
     
  25. lucbloom

    lucbloom

    Joined:
    Feb 10, 2017
    Posts:
    1
    Please change that into
    Code (CSharp):
    1.     if ((resolution.x != Screen.width || resolution.y != Screen.height) && (resolution.x != Screen.height || resolution.y != Screen.width))
    2.  
    Otherwise if you go from e.g. 600x500 to 500x500 it won't notice.
    [EDIT]
    Not that that would ever happen :)
     
  26. ProtoTerminator

    ProtoTerminator

    Joined:
    Nov 19, 2013
    Posts:
    13
    Good catch. It could also be improved to check if the orientation was changed or not to detect a 600x500 => 500x600 without rotating.

    Code (CSharp):
    1.     if ((resolution.x != Screen.width || resolution.y != Screen.height) && (!orientationChanged || resolution.x != Screen.height || resolution.y != Screen.width))
    2.  
     
  27. AiRobotMedia

    AiRobotMedia

    Joined:
    Jun 13, 2018
    Posts:
    61
    Add to a canvas stretched full screen

    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3. using UnityEngine.EventSystems;
    4.  
    5. [RequireComponent(typeof(RectTransform))]
    6. public class UiMonitor : Singleton<UiMonitor>
    7. {
    8.     public RectTransform rectTransform;
    9.  
    10.     public event EventHandler<DimensionsChangedEventArgs> DimensionsChanged;
    11.  
    12.     private void Start()
    13.     {
    14.         rectTransform = GetComponent<RectTransform>();
    15.     }
    16.  
    17.     protected void OnRectTransformDimensionsChange()
    18.     {
    19.         //Debug.Log("RectTransformDimensionsChange firing on " + this.name + " fine.");
    20.  
    21.         if (DimensionsChanged != null)
    22.         {
    23.             int w = (int)rectTransform.rect.width;
    24.             int h = (int)rectTransform.rect.height;
    25.  
    26.             DimensionsChanged(this, new DimensionsChangedEventArgs(w, h));
    27.         }
    28.     }
    29. }
    30.  
    31. public class DimensionsChangedEventArgs : EventArgs
    32. {
    33.     public int width = 0;
    34.     public int height = 0;
    35.  
    36.     public DimensionsChangedEventArgs(int width, int height)
    37.     {
    38.         this.width = width;
    39.         this.height = height;
    40.     }
    41. }
    42.