Expo屏幕方向锁定导致iOS打开模态框时崩溃问题求助
Expo iOS横屏锁定后打开模态框崩溃+initialOrientation不生效问题排查
问题描述
用Expo开发横版游戏时碰到两个棘手问题:
- 通过
useEffect调用ScreenOrientation.lockAsync(LANDSCAPE)锁定横屏后,iOS设备打开模态框直接崩溃; - 尝试在
app.json的expo-screen-orientation插件里配置initialOrientation: "LANDSCAPE",但完全没效果。
最小复现代码
App.js
import * as ScreenOrientation from 'expo-screen-orientation'; import { Animated, Modal, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'; import { useEffect, useState } from 'react'; export default function App() { useEffect(() => { async function changeScreenOrientation() { await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.LANDSCAPE); } changeScreenOrientation(); }, []); const [modalVisible, setModalVisible] = useState(false); return ( <View style={styles.container}> <TouchableOpacity style={styles.button} onPress={() => setModalVisible(true)}> <Text style={styles.textStyle}>Open</Text> </TouchableOpacity> <Modal animationType='slide' transparent={true} visible={modalVisible} onRequestClose={() => setModalVisible(false)}> <View style={styles.centeredView}> <View style={styles.modalView}> <TouchableOpacity style={styles.button} onPress={() => setModalVisible(false)}> <Text style={styles.textStyle}>Close</Text> </TouchableOpacity> </View> </View> </Modal> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#f0f0f0', }, button: { borderRadius: 20, padding: 10, elevation: 2, marginTop: 15, backgroundColor: '#2196F3', }, textStyle: { color: 'white', fontWeight: 'bold', textAlign: 'center', }, centeredView: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: 'rgba(0,0,0,0.5)', }, modalView: { margin: 20, backgroundColor: 'white', borderRadius: 20, padding: 35, alignItems: 'center', shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.25, shadowRadius: 4, elevation: 5, }, });
app.json
{ "expo": { "name": "Player", "slug": "Player", "version": "1.0.0", "orientation": "portrait", "icon": "./assets/icon.png", "userInterfaceStyle": "light", "splash": { "image": "./assets/splash.png", "resizeMode": "contain", "backgroundColor": "#ffffff" }, "assetBundlePatterns": ["**/*"], "ios": { "supportsTablet": true, "requireFullScreen": true }, "android": { "adaptiveIcon": { "foregroundImage": "./assets/adaptive-icon.png", "backgroundColor": "#ffffff" } }, "web": { "favicon": "./assets/favicon.png" }, "plugins": [ [ "expo-screen-orientation", { "initialOrientation": "LANDSCAPE" } ] ] } }
解决方案
1. iOS模态框崩溃修复
iOS上模态框默认会强制竖屏,和全局横屏锁冲突导致崩溃。解决办法是在模态框显示/隐藏时动态调整方向锁:
- 打开模态框时临时解锁方向,允许系统自动适配
- 关闭模态框后重新锁定横屏
修改后的核心代码:
// 新增两个回调函数 const handleModalShow = async () => { await ScreenOrientation.unlockAsync(); }; const handleModalDismiss = async () => { await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.LANDSCAPE); }; // 给Modal组件添加回调 <Modal animationType='slide' transparent={true} visible={modalVisible} onRequestClose={() => setModalVisible(false)} onShow={handleModalShow} onDismiss={handleModalDismiss} > {/* 模态框内容不变 */} </Modal>
2. initialOrientation配置不生效修复
你的app.json里根节点的"orientation": "portrait"和插件的initialOrientation冲突了,Expo优先取根节点配置。只需修改根节点的orientation为横屏即可:
{ "expo": { // ...其他配置 "orientation": "landscape", // 把portrait改成landscape // ...插件配置可保留或删除,根节点配置已足够 } }
注意事项
- 修改
app.json的orientation后,必须重新构建native项目(eas build或expo run:ios),热重载不会生效 - Expo Go可能无法加载native层面的配置,建议用自定义开发客户端测试
内容的提问来源于stack exchange,提问作者Shep Sims
相关产品推荐
相关产品推荐

