欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.net

在这里插入图片描述

📋 前言

屏幕方向控制是移动应用开发中的常见需求,特别是在视频播放、游戏、全屏图片浏览等场景中,需要根据内容类型动态调整屏幕方向。react-native-orientation-locker 是一个功能强大的屏幕方向控制库,支持锁定屏幕方向、监听方向变化、获取当前方向等功能,是开发横竖屏切换应用的必备工具。

🎯 库简介

基本信息

  • 库名称: react-native-orientation-locker
  • 版本信息:
    • 1.7.0-0.0.7 + @react-native-oh-tpl/react-native-orientation-locker: 支持 RN 0.72 版本(已废弃)
    • 1.7.1+ + @react-native-ohos/react-native-orientation-locker: 支持 RN 0.72/0.77 版本
  • 官方仓库: https://github.com/wonday/react-native-orientation-locker
  • 鸿蒙仓库: https://atomgit.com/openharmony-sig/rntpc_react-native-orientation-locker
  • 主要功能:
    • 📱 锁定屏幕方向(竖屏、横屏、左横屏、右横屏)
    • 🔄 监听屏幕方向变化
    • 🔓 解锁屏幕方向,允许自由旋转
    • 📐 获取当前设备方向
    • 🎯 支持方向锁定状态监听

为什么需要屏幕方向控制库?

特性 原生开发 react-native-orientation-locker
方向锁定 ⚠️ 需调用原生API ✅ 统一接口
方向监听 ⚠️ 需原生模块 ✅ 事件回调机制
跨平台一致性 ⚠️ iOS/Android差异 ✅ 统一行为
Hook支持 ❌ 需自行实现 ✅ 内置useOrientationChange
HarmonyOS 支持 ❌ 无 ✅ 完善适配

核心功能

功能 说明 HarmonyOS 支持
lockToPortrait() 锁定为竖屏
lockToLandscape() 锁定为横屏
lockToLandscapeLeft() 锁定为左横屏
lockToLandscapeRight() 锁定为右横屏
lockToPortraitUpsideDown() 锁定为倒置竖屏
unlockAllOrientations() 解锁所有方向
getOrientation() 获取当前UI方向
getDeviceOrientation() 获取设备物理方向
addOrientationListener() 添加方向变化监听
addDeviceOrientationListener() 添加设备方向监听
addLockListener() 添加锁定状态监听

兼容性验证

在以下环境验证通过:

  • RNOH: 0.72.90; SDK: HarmonyOS 6.0.0 Release SDK; IDE: DevEco Studio 6.0.2; ROM: 6.0.0

📦 安装步骤

1. 安装依赖

请到三方库的 Releases 发布地址查看配套的版本信息:

三方库版本 发布信息 支持 RN 版本
1.7.0-0.0.7 @react-native-oh-tpl/react-native-orientation-locker 0.72(已废弃)
1.7.1+ @react-native-ohos/react-native-orientation-locker 0.72/0.77

在这里插入图片描述

# RN 0.72 版本(推荐使用新版本)
npm install @react-native-ohos/react-native-orientation-locker@1.7.1-rc.1

# RN 0.77 版本
npm install @react-native-ohos/react-native-orientation-locker@1.8.0-rc.1

# 或者使用 yarn
yarn add @react-native-ohos/react-native-orientation-locker

2. 验证安装

安装完成后,检查 package.json 文件:

{
  "dependencies": {
    "@react-native-ohos/react-native-orientation-locker": "^1.7.1-rc.1"
  }
}

🔧 HarmonyOS 平台配置 ⭐

1. 在工程根目录的 oh-package.json5 添加 overrides 字段(看自己package.json中的版本)

打开 harmony/oh-package.json5,添加以下配置:

{
  // ... 其他配置
  "overrides": {
    "@rnoh/react-native-openharmony": "0.72.90"
  }
}

2. 引入原生端代码

打开 harmony/entry/oh-package.json5,添加以下依赖:

"dependencies": {
  "@react-native-ohos/react-native-orientation-locker": "file:../../node_modules/@react-native-ohos/react-native-orientation-locker/harmony/orientation_locker.har"
}

点击右上角的 sync 按钮,或者在终端执行:

cd entry
ohpm install

3. 配置 CMakeLists

打开 entry/src/main/cpp/CMakeLists.txt,添加:

project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules")
+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")

add_subdirectory("${RNOH_CPP_DIR}" ./rn)

# RNOH_BEGIN: manual_package_linking_1
add_subdirectory("../../../../sample_package/src/main/cpp" ./sample-package)
+ add_subdirectory("${OH_MODULES}/@react-native-ohos/react-native-orientation-locker/src/main/cpp" ./orientation_locker)
# RNOH_END: manual_package_linking_1

add_library(rnoh_app SHARED
    ${GENERATED_CPP_FILES}
    "./PackageProvider.cpp"
    "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)

target_link_libraries(rnoh_app PUBLIC rnoh)

# RNOH_BEGIN: manual_package_linking_2
target_link_libraries(rnoh_app PUBLIC rnoh_sample_package)
+ target_link_libraries(rnoh_app PUBLIC rnoh_orientation_locker)
# RNOH_END: manual_package_linking_2

4. 引入 OrientationLockerPackage

打开 entry/src/main/cpp/PackageProvider.cpp,添加:

#include "RNOH/PackageProvider.h"
#include "generated/RNOHGeneratedPackage.h"
#include "SamplePackage.h"
+ #include "OrientationLockerPackage.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
        std::make_shared<RNOHGeneratedPackage>(ctx),
        std::make_shared<SamplePackage>(ctx),
        + std::make_shared<OrientationLockerPackage>(ctx),
    };
}

5. 在 ArkTS 侧引入 RNOrientationLockerPackage

打开 entry/src/main/ets/RNPackagesFactory.ts,添加:

import { RNOrientationLockerPackage } from '@react-native-ohos/react-native-orientation-locker/ts';

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
    new SamplePackage(ctx),
    new RNOrientationLockerPackage(ctx)
  ];
}

6. 配置权限

由于此库获取加速度传感器的数据,使用时需要配置对应的权限。在 entry/src/main/module.json5 中添加:

{
  // ... 其他配置
  "requestPermissions": [
    {
      "name": "ohos.permission.ACCELEROMETER"
    }
  ]
}

然后编译、运行即可。

📖 API 详解

lockToPortrait - 锁定为竖屏

将应用锁定为竖屏模式,设备旋转时屏幕不会跟随旋转。

类型() => void

使用场景

  • 阅读类应用
  • 表单填写页面
  • 列表浏览页面
import Orientation from 'react-native-orientation-locker';

// 锁定为竖屏
const lockPortrait = () => {
  Orientation.lockToPortrait();
};

lockToLandscape - 锁定为横屏

将应用锁定为横屏模式,自动选择左横屏或右横屏。

类型() => void

使用场景

  • 视频播放
  • 游戏应用
  • 图片浏览
import Orientation from 'react-native-orientation-locker';

// 锁定为横屏
const lockLandscape = () => {
  Orientation.lockToLandscape();
};

lockToLandscapeLeft / lockToLandscapeRight - 锁定特定横屏方向

锁定为指定的横屏方向(左横屏或右横屏)。

类型() => void

使用场景

  • 特定方向的视频播放
  • 需要固定横屏方向的游戏
  • 双人同屏游戏
import Orientation from 'react-native-orientation-locker';

// 锁定为左横屏(Home键在右侧)
Orientation.lockToLandscapeLeft();

// 锁定为右横屏(Home键在左侧)
Orientation.lockToLandscapeRight();

lockToPortraitUpsideDown - 锁定为倒置竖屏

将应用锁定为倒置竖屏模式。

类型() => void

使用场景

  • 特殊展示需求
  • 底部操作的应用
import Orientation from 'react-native-orientation-locker';

Orientation.lockToPortraitUpsideDown();

unlockAllOrientations - 解锁所有方向

解除屏幕方向锁定,允许设备自由旋转。

类型() => void

使用场景

  • 退出全屏视频
  • 恢复正常浏览模式
  • 用户自主选择方向
import Orientation from 'react-native-orientation-locker';

// 解锁所有方向
const unlockOrientation = () => {
  Orientation.unlockAllOrientations();
};

getOrientation - 获取当前UI方向

获取当前应用的UI方向(受锁定状态影响)。

类型(callback: (orientation: string) => void) => void

返回值

说明
PORTRAIT 竖屏
LANDSCAPE-LEFT 左横屏
LANDSCAPE-RIGHT 右横屏
PORTRAIT-UPSIDEDOWN 倒置竖屏
UNKNOWN 未知

使用场景

  • 根据方向调整UI布局
  • 记录用户使用习惯
  • 方向相关功能判断
import Orientation from 'react-native-orientation-locker';

Orientation.getOrientation((orientation) => {
  console.log('当前UI方向:', orientation);
  // PORTRAIT, LANDSCAPE-LEFT, LANDSCAPE-RIGHT, PORTRAIT-UPSIDEDOWN, UNKNOWN
});

getDeviceOrientation - 获取设备物理方向

获取设备实际的物理方向(不受锁定状态影响)。

类型(callback: (orientation: string) => void) => void

使用场景

  • 检测用户握持方向
  • 实现方向相关交互
  • 传感器数据处理
import Orientation from 'react-native-orientation-locker';

Orientation.getDeviceOrientation((orientation) => {
  console.log('设备物理方向:', orientation);
});

addOrientationListener - 添加方向变化监听

监听UI方向变化,当锁定方向时不会触发,直到解锁。

类型(callback: (orientation: string) => void) => void

使用场景

  • 动态调整UI布局
  • 方向变化动画
  • 数据刷新
import Orientation, { useOrientationChange } from 'react-native-orientation-locker';

// 方式一:使用监听器
useEffect(() => {
  const handleOrientationChange = (orientation) => {
    console.log('方向变化:', orientation);
    // 更新UI状态
  };
  
  Orientation.addOrientationListener(handleOrientationChange);
  
  return () => {
    Orientation.removeOrientationListener(handleOrientationChange);
  };
}, []);

// 方式二:使用Hook
const MyComponent = () => {
  useOrientationChange((orientation) => {
    console.log('方向变化:', orientation);
  });
  
  return <View>...</View>;
};

addDeviceOrientationListener - 添加设备方向监听

监听设备物理方向变化,即使锁定方向也会触发。

类型(callback: (orientation: string) => void) => void

使用场景

  • 实时检测设备姿态
  • 游戏/AR应用
  • 运动检测
import Orientation from 'react-native-orientation-locker';

useEffect(() => {
  const handleDeviceOrientation = (orientation) => {
    console.log('设备方向变化:', orientation);
  };
  
  Orientation.addDeviceOrientationListener(handleDeviceOrientation);
  
  return () => {
    Orientation.removeDeviceOrientationListener(handleDeviceOrientation);
  };
}, []);

addLockListener - 添加锁定状态监听

监听方向锁定状态的变化。

类型(callback: (orientation: string) => void) => void

返回值

说明
PORTRAIT 锁定为竖屏
LANDSCAPE-LEFT 锁定为左横屏
LANDSCAPE-RIGHT 锁定为右横屏
UNKNOWN 未锁定(自由旋转)

使用场景

  • 显示当前锁定状态
  • 锁定状态UI提示
  • 状态同步
import Orientation, { useLockListener } from 'react-native-orientation-locker';

// 方式一:使用监听器
useEffect(() => {
  const handleLockChange = (orientation) => {
    if (orientation === 'UNKNOWN') {
      console.log('屏幕方向已解锁');
    } else {
      console.log('屏幕已锁定为:', orientation);
    }
  };
  
  Orientation.addLockListener(handleLockChange);
  
  return () => {
    Orientation.removeLockListener(handleLockChange);
  };
}, []);

// 方式二:使用Hook
const MyComponent = () => {
  useLockListener((orientation) => {
    console.log('锁定状态:', orientation);
  });
  
  return <View>...</View>;
};

OrientationLocker 组件

提供声明式的方向控制组件,适合在特定场景使用。

属性

属性 类型 说明
orientation string 锁定的方向类型
onChange function 方向变化回调
onDeviceChange function 设备方向变化回调

使用场景

  • 视频播放页面
  • 全屏图片查看
  • 游戏界面
import { OrientationLocker, PORTRAIT, LANDSCAPE } from 'react-native-orientation-locker';

const VideoPlayer = ({ isFullscreen }) => {
  return (
    <View>
      <OrientationLocker
        orientation={isFullscreen ? LANDSCAPE : PORTRAIT}
        onChange={(orientation) => {
          console.log('方向变化:', orientation);
        }}
      />
      {/* 视频播放器内容 */}
    </View>
  );
};

📋 完整示例

在这里插入图片描述

import React, { useCallback, useEffect, useState } from "react";
import {
  Alert,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
  ScrollView,
} from "react-native";
import Orientation, {
  OrientationLocker,
  PORTRAIT,
  LANDSCAPE,
  LANDSCAPE_LEFT,
  LANDSCAPE_RIGHT,
  PORTRAIT_UPSIDE_DOWN,
  useOrientationChange,
  useDeviceOrientationChange,
  useLockListener,
} from "react-native-orientation-locker";

const App: React.FC = () => {
  const [orientation, setOrientation] = useState<string>("未知");
  const [deviceOrientation, setDeviceOrientation] = useState<string>("未知");
  const [lockStatus, setLockStatus] = useState<string>("未锁定");
  const [isFullscreen, setIsFullscreen] = useState(false);

  useEffect(() => {
    getOrientation();
  }, []);

  useOrientationChange((ori) => {
    setOrientation(ori);
    console.log("UI方向变化:", ori);
  });

  useDeviceOrientationChange((ori) => {
    setDeviceOrientation(ori);
    console.log("设备方向变化:", ori);
  });

  useLockListener((ori) => {
    setLockStatus(ori === "UNKNOWN" ? "未锁定" : `已锁定: ${ori}`);
    console.log("锁定状态变化:", ori);
  });

  const getOrientation = () => {
    Orientation.getOrientation((ori) => {
      if (ori) {
        setOrientation(ori);
        Alert.alert("当前屏幕方向", `UI方向: ${ori}`);
      } else {
        Alert.alert("获取失败", "无法获取当前屏幕方向");
      }
    });
  };

  const getDeviceOrientation = () => {
    Orientation.getDeviceOrientation((ori) => {
      if (ori) {
        setDeviceOrientation(ori);
        Alert.alert("当前设备方向", `设备方向: ${ori}`);
      }
    });
  };

  const lockToPortrait = useCallback(() => {
    Orientation.lockToPortrait();
    Alert.alert("锁定成功", "已锁定为竖屏");
  }, []);

  const lockToLandscape = useCallback(() => {
    Orientation.lockToLandscape();
    Alert.alert("锁定成功", "已锁定为横屏");
  }, []);

  const lockToLandscapeLeft = useCallback(() => {
    Orientation.lockToLandscapeLeft();
    Alert.alert("锁定成功", "已锁定为左横屏");
  }, []);

  const lockToLandscapeRight = useCallback(() => {
    Orientation.lockToLandscapeRight();
    Alert.alert("锁定成功", "已锁定为右横屏");
  }, []);

  const lockToPortraitUpsideDown = useCallback(() => {
    Orientation.lockToPortraitUpsideDown();
    Alert.alert("锁定成功", "已锁定为倒置竖屏");
  }, []);

  const lockToAllButUpsideDown = useCallback(() => {
    Orientation.lockToAllOrientationsButUpsideDown();
    Alert.alert("锁定成功", "已锁定除倒置外的所有方向");
  }, []);

  const unlockAll = useCallback(() => {
    Orientation.unlockAllOrientations();
    Alert.alert("解锁成功", "已解锁所有方向");
  }, []);

  const toggleFullscreen = useCallback(() => {
    setIsFullscreen((prev) => !prev);
  }, []);

  const getOrientationLabel = (ori: string) => {
    const labels: Record<string, string> = {
      PORTRAIT: "竖屏",
      "LANDSCAPE-LEFT": "左横屏",
      "LANDSCAPE-RIGHT": "右横屏",
      "PORTRAIT-UPSIDEDOWN": "倒置竖屏",
      UNKNOWN: "未知",
    };
    return labels[ori] || ori;
  };

  return (
    <View style={styles.container}>
      <OrientationLocker
        orientation={isFullscreen ? LANDSCAPE : PORTRAIT}
        onChange={(ori) => console.log("组件方向变化:", ori)}
      />

      <View style={styles.header}>
        <Text style={styles.title}>屏幕方向控制示例</Text>
      </View>

      <View style={styles.statusPanel}>
        <View style={styles.statusRow}>
          <Text style={styles.statusLabel}>UI方向:</Text>
          <Text style={styles.statusValue}>{getOrientationLabel(orientation)}</Text>
        </View>
        <View style={styles.statusRow}>
          <Text style={styles.statusLabel}>设备方向:</Text>
          <Text style={styles.statusValue}>{getOrientationLabel(deviceOrientation)}</Text>
        </View>
        <View style={styles.statusRow}>
          <Text style={styles.statusLabel}>锁定状态:</Text>
          <Text style={styles.statusValue}>{lockStatus}</Text>
        </View>
      </View>

      <ScrollView style={styles.buttonContainer}>
        <View style={styles.buttonGroup}>
          <Text style={styles.groupTitle}>方向锁定</Text>
          <TouchableOpacity style={styles.button} onPress={lockToPortrait}>
            <Text style={styles.buttonText}>锁定竖屏</Text>
          </TouchableOpacity>
          <TouchableOpacity style={styles.button} onPress={lockToLandscape}>
            <Text style={styles.buttonText}>锁定横屏</Text>
          </TouchableOpacity>
          <TouchableOpacity style={styles.button} onPress={lockToLandscapeLeft}>
            <Text style={styles.buttonText}>锁定左横屏</Text>
          </TouchableOpacity>
          <TouchableOpacity style={styles.button} onPress={lockToLandscapeRight}>
            <Text style={styles.buttonText}>锁定右横屏</Text>
          </TouchableOpacity>
          <TouchableOpacity style={styles.button} onPress={lockToPortraitUpsideDown}>
            <Text style={styles.buttonText}>锁定倒置竖屏</Text>
          </TouchableOpacity>
          <TouchableOpacity style={styles.button} onPress={lockToAllButUpsideDown}>
            <Text style={styles.buttonText}>锁定除倒置外所有方向</Text>
          </TouchableOpacity>
        </View>

        <View style={styles.buttonGroup}>
          <Text style={styles.groupTitle}>解锁与查询</Text>
          <TouchableOpacity style={[styles.button, styles.unlockButton]} onPress={unlockAll}>
            <Text style={styles.buttonText}>解锁所有方向</Text>
          </TouchableOpacity>
          <TouchableOpacity style={styles.button} onPress={getOrientation}>
            <Text style={styles.buttonText}>获取UI方向</Text>
          </TouchableOpacity>
          <TouchableOpacity style={styles.button} onPress={getDeviceOrientation}>
            <Text style={styles.buttonText}>获取设备方向</Text>
          </TouchableOpacity>
        </View>

        <View style={styles.buttonGroup}>
          <Text style={styles.groupTitle}>全屏模式演示</Text>
          <TouchableOpacity
            style={[styles.button, isFullscreen && styles.activeButton]}
            onPress={toggleFullscreen}
          >
            <Text style={styles.buttonText}>
              {isFullscreen ? "退出全屏" : "进入全屏(横屏)"}
            </Text>
          </TouchableOpacity>
        </View>
      </ScrollView>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#F5F5F5",
  },
  header: {
    padding: 16,
    backgroundColor: "#007AFF",
    alignItems: "center",
  },
  title: {
    fontSize: 18,
    fontWeight: "600",
    color: "#FFF",
  },
  statusPanel: {
    backgroundColor: "#FFF",
    padding: 16,
    borderBottomWidth: 1,
    borderBottomColor: "#E5E5EA",
  },
  statusRow: {
    flexDirection: "row",
    justifyContent: "space-between",
    marginBottom: 8,
  },
  statusLabel: {
    fontSize: 14,
    color: "#666",
  },
  statusValue: {
    fontSize: 14,
    fontWeight: "500",
    color: "#333",
  },
  buttonContainer: {
    flex: 1,
    padding: 16,
  },
  buttonGroup: {
    marginBottom: 24,
  },
  groupTitle: {
    fontSize: 16,
    fontWeight: "600",
    color: "#333",
    marginBottom: 12,
  },
  button: {
    backgroundColor: "#007AFF",
    paddingVertical: 14,
    paddingHorizontal: 20,
    borderRadius: 8,
    marginBottom: 10,
    alignItems: "center",
  },
  unlockButton: {
    backgroundColor: "#34C759",
  },
  activeButton: {
    backgroundColor: "#FF9500",
  },
  buttonText: {
    color: "#FFF",
    fontSize: 16,
    fontWeight: "500",
  },
});

export default App;

⚠️ 注意事项

权限配置

使用此库需要配置加速度传感器权限,否则方向检测功能无法正常工作:

// entry/src/main/module.json5
{
  "requestPermissions": [
    {
      "name": "ohos.permission.ACCELEROMETER"
    }
  ]
}

方向常量

库提供了以下方向常量,方便代码中使用:

import {
  PORTRAIT,           // 竖屏
  LANDSCAPE,          // 横屏
  LANDSCAPE_LEFT,     // 左横屏
  LANDSCAPE_RIGHT,    // 右横屏
  PORTRAIT_UPSIDE_DOWN, // 倒置竖屏
} from 'react-native-orientation-locker';

监听器清理

使用监听器时,务必在组件卸载时移除监听,避免内存泄漏:

useEffect(() => {
  Orientation.addOrientationListener(handleOrientation);
  return () => {
    Orientation.removeOrientationListener(handleOrientation);
  };
}, []);
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐