Expo React Native中Pressable切换图片时显示延迟问题咨询
解决React Native条件渲染图片的位置切换延迟问题
问题描述
我是Expo和React Native新手,正在学习条件渲染,测试时发现条件渲染的图片存在显示延迟问题:当Pressable包裹的图片随状态变量变化同时切换源和屏幕位置时,它会先在原位置显示新图片,再根据top属性移动(还会显示整个位移过程)。希望图片位置调整完成后再整体显示,避免每次点击按钮切换图片出现这种延迟。
源代码
import { StatusBar } from 'expo-status-bar'; import { Pressable, StyleSheet, Text, TextInput, View, ScrollView, Image, Dimensions } from 'react-native'; import Constants from 'expo-constants'; import { Card } from 'react-native-paper'; import login from './login-screen.png'; import loginButton from './login-screen-button.png'; import loginButtonPressed from './loginButton2.png'; import ID_selected from './ID_selected.png'; import {useState} from 'react'; //Iphone 12 pro max resolution: 1284 x 2778 pixels export default function App() { const win = Dimensions.get('window'); const ratio = win.width / 428; const [text, onChangeText] = useState(); const [isShowingImageID, setShowingImageID] = useState(false); const [isShowingImagePW, setShowingImagePW] = useState(false); const [pressed, onPressFunction] = useState(false); console.log("Window.width: ", win.width); console.log("Windows.height: ", win.height); return ( <View style={styles.container}> <Image source={login} style={{ width: 428, height: 926, }} /> <Pressable onPressIn={() => onPressFunction(true)} onPressOut={() => onPressFunction(false)} style={{ position: "absolute" }} > { pressed ? ( <Image source={loginButtonPressed} style={{ width: 428, height: 926, top: 50, position: "relative" }} /> ) : ( <Image source={loginButton} style={{ width: 428, height: 926, position: "relative" }} /> ) } </Pressable> { isShowingImageID ? ( <Image source={ID_selected} style={{ width: 1184 / 3, height: 140 / 3, position: "absolute", top: 295 }} /> ) : (null) } { isShowingImagePW ? ( <Image source={ID_selected} style={{ width: 1184 / 3, height: 140 / 3, position: "absolute", top: 338 }} /> ) : (null) } <TextInput style={textInputStyleID.container} onChangeText={text => onChangeText(text)} onPressIn={touchEvt => setShowingImageID(true)} onPressOut={touchEvt => setShowingImageID(false)} placeholder="아이디" placeholderTextColor="#A9A9A9" keyboardType="email-address" /> <TextInput style={textInputStylePW.container} onChangeText={text => onChangeText(text)} onPressIn={touchEvt => setShowingImagePW(true)} onPressOut={touchEvt => setShowingImagePW(false)} placeholder="비밀번호" placeholderTextColor="#A9A9A9" keyboardType="default" secureTextEntry={true} /> <StatusBar style="auto" /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', position: 'absolute' }, }); const textInputStyleID = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', position: 'absolute', top: 303, left: 42, width: 350, height: 30 } }); const textInputStylePW = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', position: 'absolute', top: 346, left: 42, width: 350, height: 30 } });
解决方案
1. 统一定位逻辑,避免组件重排延迟
当前Pressable用absolute定位,内部图片用relative定位,切换时修改图片top会触发重排。将定位逻辑移到Pressable上,内部图片保持静态尺寸:
<Pressable onPressIn={() => onPressFunction(true)} onPressOut={() => onPressFunction(false)} style={[{ position: "absolute", top: pressed ? 50 : 0, }]} > <Image source={pressed ? loginButtonPressed : loginButton} style={{ width: 428, height: 926, position: "absolute" }} /> </Pressable>
状态切换时仅修改Pressable的top值,图片始终填满容器,不会出现先显示再移动的问题。
2. 预加载图片,消除加载延迟
图片首次加载的时间也会导致延迟,在组件挂载时预加载所有需要切换的图片:
import { useState, useEffect } from 'react'; export default function App() { // ...其他状态定义 useEffect(() => { Image.prefetch(loginButtonPressed); Image.prefetch(ID_selected); }, []); // ...其余代码 }
3. 优化条件渲染,避免组件重复卸载/挂载
当前ID和PW的图片通过条件渲染挂载/卸载,会导致组件重建。改用opacity控制显示,保持组件始终存在:
<Image source={ID_selected} style={{ width: 1184 / 3, height: 140 / 3, position: "absolute", top: 295, opacity: isShowingImageID ? 1 : 0, pointerEvents: isShowingImageID ? 'auto' : 'none' }} /> <Image source={ID_selected} style={{ width: 1184 / 3, height: 140 / 3, position: "absolute", top: 338, opacity: isShowingImagePW ? 1 : 0, pointerEvents: isShowingImagePW ? 'auto' : 'none' }} />
4. 用Animated库实现精准过渡(可选)
如果需要平滑动画而非瞬间切换,使用React Native的Animated库控制过渡:
import { Animated } from 'react-native'; export default function App() { const pressedAnim = new Animated.Value(0); const onPressIn = () => { Animated.timing(pressedAnim, { toValue: 1, duration: 0, useNativeDriver: false, }).start(); }; const onPressOut = () => { Animated.timing(pressedAnim, { toValue: 0, duration: 0, useNativeDriver: false, }).start(); }; const topValue = pressedAnim.interpolate({ inputRange: [0, 1], outputRange: [0, 50], }); // ...其余代码 return ( <View style={styles.container}> {/* 其他组件 */} <Animated.View style={[{ position: "absolute", top: topValue, }]} > <Pressable onPressIn={onPressIn} onPressOut={onPressOut}> <Image source={pressedAnim._value === 1 ? loginButtonPressed : loginButton} style={{ width: 428, height: 926 }} /> </Pressable> </Animated.View> {/* 其他组件 */} </View> ); }
内容的提问来源于stack exchange,提问作者rasputin
相关产品推荐
相关产品推荐

