React Native 屏幕旋转时如何更新尺寸实现组件自适应调整
报错原因
你触发Invalid hook call错误的核心原因是:useState、useEffect属于React Hooks,只能在React函数组件、自定义Hook的顶层作用域调用,你在普通JS文件的普通函数里调用Hooks,不符合Hooks的使用规则。
另外你当前的样式是初始化时静态生成的,直接写死了初始的屏幕宽高,就算监听生效,静态样式也不会自动更新,自然无法适配旋转后的尺寸。
可行实现方案
推荐使用React Native官方自带的useWindowDimensions Hook,它会自动监听屏幕尺寸变化,无需手动维护Dimensions监听器,实现步骤如下:
1. 修改Styles.js,改为动态生成样式
不要导出静态的样式对象,改为导出一个接收当前屏幕宽高为参数的函数,动态生成对应尺寸的样式:
import { StyleSheet, Dimensions } from "react-native"; import { scale, ScaledSheet } from "react-native-size-matters"; // 改为接收宽高参数的函数,动态生成样式 export const getStyles = (windowWidth, windowHeight) => ScaledSheet.create({ scrollViewContainer: { backgroundColor: '#E20030', alignItems: 'center', height: windowHeight, padding: '50@s' }, container2: { alignItems: 'center', justifyContent: 'center', width: windowWidth, flex: 1, }, loginRect: { borderRadius: '30@s', marginTop: '20@s', width: windowWidth * 0.8, backgroundColor: 'white', alignItems: 'center' }, SectionStyle: { flexDirection: 'row', marginTop: 0, marginLeft: '35@s', marginRight: '35@s', borderWidth: '1@s', borderRadius: '5@s', borderColor: '#dadae8', }, // 你之前缺失的input、buttonTextStyle样式也可以在这里补充 });
2. 修改Login.js,使用useWindowDimensions获取实时尺寸
在登录组件内调用useWindowDimensions获取实时的宽高,再传入样式生成函数得到当前适配的样式:
import React from 'react'; import { Text, View, TextInput, TouchableOpacity, KeyboardAvoidingView, useWindowDimensions // 导入官方Hook } from 'react-native'; import { getStyles } from './Components/styles'; // 导入样式生成函数 const LoginScreen = () => { // 获取实时屏幕宽高,旋转时会自动更新 const { width: windowWidth, height: windowHeight } = useWindowDimensions(); // 生成当前尺寸对应的样式 const { mystyles, styles } = getStyles(windowWidth, windowHeight); return ( <View style={mystyles.scrollViewContainer}> <KeyboardAvoidingView behavior="padding" style={{ flex: 100 }}> <View style={mystyles.scrollViewContainer}> <View style={mystyles.loginRect}> <View style={{ flexDirection: 'row' }}> <View style={{ flex: 1, marginLeft: 45, marginTop: 20 }}> <Text style={{ color: 'black' }}>Username</Text> </View> </View> <View style={styles.SectionStyle}> <TextInput style={styles.input} /> </View> <View style={{ flexDirection: 'row' }}> <View style={{ flex: 1, marginLeft: 45, marginTop: 20 }}> <Text style={{ color: 'black' }}>Password</Text> </View> </View> <View style={styles.SectionStyle}> <TextInput style={styles.input} /> </View> <TouchableOpacity> <Text style={styles.buttonTextStyle}>LOGIN</Text> </TouchableOpacity> </View> </View> </KeyboardAvoidingView> </View> ) } export default LoginScreen;
方案说明
- 屏幕旋转时
useWindowDimensions会自动返回最新的宽高数值,触发组件重渲染,样式会根据新的尺寸重新生成,自动适配布局 - 不需要手动维护Dimensions监听器,也避免了Hooks使用错误的问题
内容的提问来源于stack exchange,提问作者Benson Kiprono
相关产品推荐
相关产品推荐

