reactjsreact-nativeexposcreen-orientation

React Native Expo orientation listener without changing orientation


I'm tryin to detect the current orientaiton on my React Native app without having to change the orientation. I made a camera app and I want to flip the icons only when the orientation changes. Right now I can't use ScreenOrientation.addOrientationChangeListener(listener) without the actual orientation changing. Any ways around this?


Solution

  • If I understand you correctly, the requirement is to get the device orientation even though the actual orientation has not been changed because it locked by orientation.

    You can use DeviceMotion module to get the device rotation (Euler angle)

    The exact calculation is taken from https://github.com/expo/expo/issues/2430#issuecomment-538074235

    function orientationCalculation(gamma: number, beta: number) {
      let ABSOLUTE_GAMMA = Math.abs(gamma);
      let ABSOLUTE_BETA = Math.abs(beta);
      let isGammaNegative = Math.sign(gamma) == -1;
      let orientation = 0;
    
      if (ABSOLUTE_GAMMA <= 0.04 && ABSOLUTE_BETA <= 0.24) {
        //Portrait mode, on a flat surface.
        orientation = 0;
      } else if (
        (ABSOLUTE_GAMMA <= 1.0 || ABSOLUTE_GAMMA >= 2.3) &&
        ABSOLUTE_BETA >= 0.5
      ) {
        //General Portrait mode, accounting for forward and back tilt on the top of the phone.
        orientation = 0;
      } else {
        if (isGammaNegative) {
          //Landscape mode with the top of the phone to the left.
          orientation = -90;
        } else {
          //Landscape mode with the top of the phone to the right.
          orientation = 90;
        }
      }
      return orientation;
    }
    
    DeviceMotion.addListener(({ orientation, rotation }) => {
      setOrientation(
        orientationCalculation(rotation.gamma, rotation.beta) === 0
          ? 'protrait'
          : 'landscape'
      );
    });
    

    Expo demo: https://expo.dev/@moshfeu/detect-orientation-by-device-motion?serviceType=classic&distribution=expo-go

    Source code: https://github.com/moshfeu/detect-orientation-by-device-motion/


    Older Answer

    DeviceMotion.addListener(({rotation}) => {
      const alpha = Math.abs(rotation.alpha);
      this.setState({
        orientation: alpha > 3 || (alpha > 0 && alpha < 0.5) ? 'landscape' : 'protrait'
      });
    });
    

    Live demo: https://expo.io/@moshfeu/snack-dc115508-fab4-4be4-818a-5a03f89725bd


    Oldest Answer

    If I understand you correctly, you want to get the current orientation on the app is load without the user changing the orientation.

    If so, you can get it from ScreenOrientation.getOrientationAsync() which will return a Promise with one of the possible values

    ScreenOrientation.getOrientationAsync().then(data => this.setState({data}));
    

    Live example: https://snack.expo.io/@moshfeu/ff4c76