反应原生模态时间延迟和生涩的动画
Posted
技术标签:
【中文标题】反应原生模态时间延迟和生涩的动画【英文标题】:react native modal time delay and jerky animation 【发布时间】:2020-07-22 10:37:40 【问题描述】:我正在尝试构建一个具有左右轮播的反应原生屏幕,在轮播的每个面板中都有一个带有项目列表的垂直平面列表。最多有 8-10 个轮播面板和 5-30 个项目在平面垂直平面列表中,因此在渲染的最多项目中可能有 300 个,但通常是 100 个。
我正在调用 API 并每隔 2-3 秒检查一次服务器上的数据,并使用新数据设置组件中的状态。这目前有效,并且子组件中的数据数据会按应有的方式更新。
平面列表中的每个项目都是可点击的,这会触发在页面中启动的模式弹出窗口。我遇到的问题是模式弹出窗口需要 4-5 秒才能出现和关闭。此外,当模态框最终开始消失时,动画会变得生涩,并且深色背景层似乎会在移除时闪烁。
我首先尝试了内置 modal 并且还使用了 react-native-modal 包,两者都是相同的。
我尝试使用 InteractionManager.runAfterInteractions 和 shouldComponentUpdate(nextProps, nextState) 尝试阻止我的 api 调用,直到动画完成或阻止我的 isModalVisible 状态属性在我更改它时导致重新渲染。
下面的代码,任何帮助将不胜感激。
import
Text,
Button,
StyleSheet,
View,
FlatList,
Dimensions,
Image,
Animated,
SafeAreaView,
TouchableHighlight,
InteractionManager,
from 'react-native';
import React from 'react';
import Title from './Title';
import CarouselMeeting from './CarouselMeeting';
import Modal from 'react-native-modal';
import Carousel from 'react-native-snap-carousel';
class MeetingDisplay extends React.Component
constructor(props)
super(props);
this.state =
raceList: [],
meetingList: [],
meetingId: props.navigation.state.params.meetingId,
currentIndex: 0,
raceCount: 0,
activeIndex: 0,
isModalVisible: false,
this.refreshScreen = this.refreshScreen.bind(this)
componentDidMount()
InteractionManager.runAfterInteractions(() =>
Promise.all([fetch('http://apicallurl?id' + this.state.meetingId), fetch('http://apicallurl?id' + this.state.meetingId)])
.then(([res1, res2]) =>
return Promise.all([res1.json(), res2.json()])
)
.then(([res1, res2]) =>
this.setState(
raceList: res1,
meetingList: res2.Meets,
)
);
this.interval = setInterval(() => this.updateRaceList(), 3000);
);
componentDidUpdate(prevProps, prevState)
InteractionManager.runAfterInteractions(() =>
if (prevState.meetingId !== this.state.meetingId)
Promise.all([fetch('http://apicallurl?id' + this.state.meetingId), fetch('http://apicallurl?id' + this.state.meetingId)])
.then(([res1, res2]) =>
return Promise.all([res1.json(), res2.json()])
)
.then(([res1, res2]) =>
this.setState(
raceList: res1,
meetingList: res2.Meets,
)
);
);
async updateRaceList()
InteractionManager.runAfterInteractions(() =>
fetch('http://apicallurl' + this.state.meetingId)
.then((response) => response.json())
.then((responseJson) =>
this.setState(
raceList: responseJson,
, function ()
);
)
.catch((error) =>
console.error(error);
);
);
toggleModal = () =>
InteractionManager.runAfterInteractions(() =>
this.setState( isModalVisible: !this.state.isModalVisible );
);
;
shouldComponentUpdate(nextProps, nextState)
if(this.state.isModalVisible !== nextState.isModalVisible)
this.setState( isModalVisible: nextState.isModalVisible)
return false;
else return true;
render()
const peek = 20;
const gutter = peek / 4;
const cardWidth = Dimensions.get('window').width - gutter * 2 - peek * 2;
const contentOffset = (Dimensions.get('window').width - (cardWidth + (gutter * 2))) / 2;
return (
<>
<Title heading=this.state.raceList.VenueName />
<SafeAreaView style= flex: 1, backgroundColor: 'rebeccapurple', paddingTop: 50, >
<View style= flex: 1, flexDirection: 'row', justifyContent: 'center', >
<Carousel
layout="default"
useScrollView
ref=ref => this.Carousel = ref
data=this.state.raceList.RaceList
sliderWidth=cardWidth
itemWidth=cardWidth - gutter * 2 - peek * 2
onSnapToItem=index => this.setState( activeIndex: index )
renderItem=( item ) => (
<Animated.View style=
flex: 1,
paddingTop: 20,
width: cardWidth,
margin: gutter,
backgroundColor: 'blue',
justifyContent: 'center',
alignItems: 'center',
>
<FlatList
horizontal=false
showsVerticalScrollIndicator=true
legacyImplementation=false
data=item.runner_list
keyExtractor=(item, index) => index.toString()
renderItem=( item , index) =>
<TouchableHighlight style= flex: 1, flexDirection: 'row' onPress=this.toggleModal >
<Image style= width: 50, height: 50 source= uri: item.imageurl />
</TouchableHighlight>
>
</FlatList>
</Animated.View>
)
/>
</View>
</SafeAreaView>
<Modal isVisible=this.state.isModalVisible
backdropTransitionOutTiming=1>
<View style= flex: 1 >
<Text>Hello!</Text>
<Button title="Hide modal" onPress=this.toggleModal />
</View>
</Modal>
</>
);
const styles = StyleSheet.create(
centeredView:
flex: 1,
justifyContent: "center",
alignItems: "center",
marginTop: 22
,
modalView:
margin: 20,
backgroundColor: "white",
borderRadius: 20,
padding: 35,
alignItems: "center",
shadowColor: "#000",
shadowOffset:
width: 0,
height: 2
,
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5
,
openButton:
backgroundColor: "#F194FF",
borderRadius: 20,
padding: 10,
elevation: 2
,
textStyle:
color: "white",
fontWeight: "bold",
textAlign: "center"
,
modalText:
marginBottom: 15,
textAlign: "center"
);
export default MeetingDisplay;
尝试 1
我有一个想法,这可能是我使用了一个名为“react-native-snap-carousel”的第三方轮播库,所以我试图用一个看起来很糟糕的滚动视图来替换它,并让我的所有平面列表/项目都在其中呈现但这并没有改善弹出时间延迟,仍然是 2-3 秒。
尝试 2
我发现了一个叫做 react.purecomponent 的东西,它可能应该对状态/道具进行浅层比较,并且只在项目/状态实际发生变化时触发重新渲染,这可能意味着动画/ui线程无论是什么导致问题停止。但是在模态显示之前仍然没有更好的暂停(无论是在模拟器上还是在设备上)
class MeetingDisplay extends React.PureComponent
尝试 4
通过在底部轮播下方的页面底部放置一个按钮来触发平面列表之外的模式,从而将平面列表排除在外。
....</View>
</SafeAreaView>
<Modal
visible=this.state.isModalVisible
backdropTransitionOutTiming=1
>
<View style= flex: 1 >
<Text>Hello!</Text>
<Button title="Hide modal" onPress=this.toggleModal />
</View>
</Modal>
<Button title="Show modal" onPress=this.toggleModal />
</>
);....
这并没有导致任何改进或性能。那么还有什么导致这个问题。是因为间隔导致我的组件不断重新渲染吗?因此,必须有一种方法可以暂停我缺少的组件重新渲染。有人吗?
【问题讨论】:
【参考方案1】:我遇到了同样的问题,并通过将以下道具添加到模态来解决它
useNativeDriver=true
请参考这个对我有帮助的答案, https://***.com/a/62020910/10432212
【讨论】:
非常感谢!!这是解决我问题的唯一方法以上是关于反应原生模态时间延迟和生涩的动画的主要内容,如果未能解决你的问题,请参考以下文章