
在 Expo 应用中,iOS 默认支持视频全屏时自动旋转,但 Android 需手动解锁屏幕方向;本文详解如何通过 expo-screen-orientation 动态控制全屏状态下的方向锁定与释放,实现跨平台一致的全屏体验。
在 expo 应用中,ios 默认支持视频全屏时自动旋转,但 android 需手动解锁屏幕方向;本文详解如何通过 `expo-screen-orientation` 动态控制全屏状态下的方向锁定与释放,实现跨平台一致的全屏体验。
在使用 expo-av 的 <Video /> 组件时,useNativeControls 启用原生播放控件后,iOS 会自动在全屏模式下允许设备自由旋转(即使应用整体锁定为 portrait),而 Android 默认仍强制保持 portrait 方向——这是 Expo 在 Android 平台上的默认行为限制,并非 Bug,而是需开发者显式干预。
要解决该问题,核心思路是:监听视频全屏状态变化,在进入全屏时动态解锁屏幕方向,退出全屏时恢复锁定。这需要借助 expo-screen-orientation 模块进行细粒度控制。
✅ 步骤一:安装依赖
npx expo install expo-screen-orientation # 或 npm install expo-screen-orientation # 如使用 yarn yarn add expo-screen-orientation
⚠️ 注意:expo-screen-orientation 是 Expo SDK 的受管模块,务必使用 npx expo install 安装以确保版本兼容性(尤其在 SDK 49+ 中)。
✅ 步骤二:配置 app.json(可选但推荐)
将应用初始方向设为 "default"(而非 "portrait"),以便系统层面允许旋转基础能力:
{
"expo": {
"name": "myApp",
"slug": "myApp",
"version": "1.0.0",
"orientation": "default",
"android": {
"adaptiveIcon": { ... }
}
}
}? 说明:"default" 表示遵循系统默认行为(即允许旋转),但不意味着整个 App 自由旋转——我们仍会在非全屏时主动锁回 portrait,因此不影响常规 UI 布局。
✅ 步骤三:实现全屏方向动态控制
更新你的 VideoPlayer 组件,添加 onFullscreenUpdate 回调并集成屏幕方向控制逻辑:
import React, { useRef } from 'react';
import { View } from 'react-native';
import { Video, ResizeMode } from 'expo-av';
import * as ScreenOrientation from 'expo-screen-orientation';
export function VideoPlayer({ videoURL }: { videoURL: string }) {
const videoRef = useRef<Video>(null);
const handleFullscreenUpdate = async ({ fullscreenUpdate }: { fullscreenUpdate: number }) => {
// Expo AV 的 fullscreenUpdate 值含义(Android/iOS 一致):
// 0 = FULLSCREEN_UPDATE_PLAYER_DID_PRESENT → 进入全屏
// 1 = FULLSCREEN_UPDATE_PLAYER_WILL_PRESENT → 即将进入(可选处理)
// 2 = FULLSCREEN_UPDATE_PLAYER_DID_DISMISS → 退出全屏
// 3 = FULLSCREEN_UPDATE_PLAYER_WILL_DISMISS → 即将退出
try {
if (fullscreenUpdate === 0 || fullscreenUpdate === 1) {
// 进入全屏:解锁方向,允许横竖屏切换
await ScreenOrientation.unlockAsync();
} else if (fullscreenUpdate === 2 || fullscreenUpdate === 3) {
// 退出全屏:重新锁定为竖屏(保持 App 主体方向一致)
await ScreenOrientation.lockAsync(
ScreenOrientation.OrientationLock.PORTRAIT
);
}
} catch (error) {
console.warn('Screen orientation change failed:', error);
}
};
return (
<View style={{ flex: 1 }}>
<Video
ref={videoRef}
source={{ uri: videoURL }}
style={{
width: '100%',
aspectRatio: 16 / 9,
alignSelf: 'center',
borderRadius: 10,
backgroundColor: 'black',
}}
useNativeControls
resizeMode={ResizeMode.CONTAIN}
hideControlsTimeoutMillis={5000}
onFullscreenUpdate={handleFullscreenUpdate}
/>
</View>
);
}? 关键注意事项
- 仅 Android 需此逻辑:iOS 原生已支持,上述代码在 iOS 上执行 unlockAsync() 无副作用,可安全共用。
- 避免重复调用:ScreenOrientation.unlockAsync() 和 lockAsync() 是异步操作,务必用 try/catch 包裹防止 Promise 拒绝中断流程。
- Ref 必须绑定:若需调用 presentFullscreenPlayer() 等方法,ref 不可省略。
- SDK 版本兼容性:确认你使用的 Expo SDK ≥ 47(推荐 SDK 49+),旧版中 fullscreenUpdate 枚举值可能未对齐,直接使用数字判断更稳定(如上例所示)。
- 权限无需额外声明:expo-screen-orientation 在 Android 上无需 AndroidManifest.xml 配置,Expo 自动处理。
✅ 效果验证
- ✅ 点击原生全屏按钮 → 屏幕自动横屏(无论设备当前朝向)
- ✅ 手动旋转设备 → 视频视图实时响应方向变化
- ✅ 点击返回/退出全屏 → 立即恢复竖屏锁定,App 其他页面不受影响
通过该方案,你无需全局放开应用方向,即可精准、可靠地实现 Android 与 iOS 一致的视频全屏旋转体验——专业、轻量、零侵入。


















