android - React-Native Animated 在低端 Android 手机中落后
问题描述
我正在尝试实现一个应该在 iOS 和 Android 设备上运行的动画。
在 iOS 中,性能似乎令人满意(使用 iPhone 6 Plus 及更高版本进行测试)。
另一方面,对于某些 Android 设备,动画滞后。
问题是,可以采取哪些措施来避免性能问题(除了useNativeDriver={true}
代码中已经存在的指令的使用)?
代码是这样的:
import * as React from 'react';
import {
Animated,
ImageBackground,
StyleSheet,
Image,
Easing,
TextInput,
View,
Text,
} from 'react-native';
import { PanGestureHandler, State } from 'react-native-gesture-handler';
import backImg from './background.png';
const c_initial_coordinate_left = 100;
const c_initial_coordinate_top = 100;
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.spaceAnimatedTranslations = new Animated.ValueXY();
this.spaceAnimatedTranslations2 = new Animated.ValueXY();
this.spaceAnimatedTranslations3 = new Animated.ValueXY();
this.spaceAnimatedTranslations4 = new Animated.ValueXY();
this.spaceAnimatedTranslations5 = new Animated.ValueXY();
this.spaceAnimatedTranslations.addListener(value => (this.spaceAnimatedTranslations_value = value));
this.spaceAnimatedTranslations2.addListener(value => (this.spaceAnimatedTranslations_value2 = value));
this.spaceAnimatedTranslations3.addListener(value => (this.spaceAnimatedTranslations_value3 = value));
this.spaceAnimatedTranslations4.addListener(value => (this.spaceAnimatedTranslations_value4 = value));
this.spaceAnimatedTranslations5.addListener(value => (this.spaceAnimatedTranslations_value5 = value));
this._animatedStyle = {transform: [{ translateX: this.spaceAnimatedTranslations.x }, { translateY: this.spaceAnimatedTranslations.y },],};
this._animatedStyle2 = {transform: [{ translateX: this.spaceAnimatedTranslations2.x }, { translateY: this.spaceAnimatedTranslations2.y },],};
this._animatedStyle3 = {transform: [{ translateX: this.spaceAnimatedTranslations3.x }, { translateY: this.spaceAnimatedTranslations3.y },],};
this._animatedStyle4 = {transform: [{ translateX: this.spaceAnimatedTranslations4.x }, { translateY: this.spaceAnimatedTranslations4.y },],};
this._animatedStyle5 = {transform: [{ translateX: this.spaceAnimatedTranslations5.x }, { translateY: this.spaceAnimatedTranslations5.y },],};
}
onSpaceMove(event) {
let l_panTranslateX = event.nativeEvent.translationX;
let l_panTranslateY = event.nativeEvent.translationY;
let l_panStartX = event.nativeEvent.x - event.nativeEvent.translationX;
let l_panStartY = event.nativeEvent.y - event.nativeEvent.translationY;
let l_animationsArray = new Array();
l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations.y, {toValue: event.nativeEvent.translationY,duration: 0,easing: Easing.linear,}));
l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations2.y, {toValue: event.nativeEvent.translationY,duration: 0,easing: Easing.linear,}));
l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations3.y, {toValue: event.nativeEvent.translationY,duration: 0,easing: Easing.linear,}));
l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations4.y, {toValue: event.nativeEvent.translationY,duration: 0,easing: Easing.linear,}));
l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations5.y, {toValue: event.nativeEvent.translationY,duration: 0,easing: Easing.linear,}));
l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations.x, {toValue: event.nativeEvent.translationX,duration: 0,easing: Easing.linear,}));
l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations2.x, {toValue: event.nativeEvent.translationX,duration: 0,easing: Easing.linear,}));
l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations3.x, {toValue: event.nativeEvent.translationX,duration: 0,easing: Easing.linear,}));
l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations4.x, {toValue: event.nativeEvent.translationX,duration: 0,easing: Easing.linear,}));
l_animationsArray.push(Animated.timing(this.spaceAnimatedTranslations5.x, {toValue: event.nativeEvent.translationX,duration: 0,easing: Easing.linear,}));
Animated.parallel(l_animationsArray).start();
this.debug_message = `\n
event.nativeEvent.translationX: ${Math.floor(
event.nativeEvent.translationX
)}
event.nativeEvent.translationY: ${Math.floor(
event.nativeEvent.translationY
)}
event.nativeEvent.absoluteX: ${Math.floor(event.nativeEvent.absoluteX)}
event.nativeEvent.absoluteY: ${Math.floor(event.nativeEvent.absoluteY)}
event.nativeEvent.x: ${Math.floor(event.nativeEvent.x)}
event.nativeEvent.y: ${Math.floor(event.nativeEvent.y)}
this.spaceAnimatedTranslations_value.x: ${Math.floor(
this.spaceAnimatedTranslations_value.x
)}
this.spaceAnimatedTranslations_value.y: ${Math.floor(
this.spaceAnimatedTranslations_value.y
)}
this.gestureStartedX: ${Math.floor(this.gestureStartedX)}
this.gestureStartedY: ${Math.floor(this.gestureStartedY)}
`;
this.forceUpdate();
}
onSpaceMoveCompleted(event) {
if (event.nativeEvent.state === State.BEGAN) {
this.spaceAnimatedTranslations.flattenOffset();
this.spaceAnimatedTranslations2.flattenOffset();
this.spaceAnimatedTranslations3.flattenOffset();
this.spaceAnimatedTranslations4.flattenOffset();
this.spaceAnimatedTranslations5.flattenOffset();
this.spaceAnimatedTranslations.setOffset({x: Math.floor(event.nativeEvent.absoluteX - c_initial_coordinate_left),y: Math.floor(event.nativeEvent.absoluteY - c_initial_coordinate_top),});
this.spaceAnimatedTranslations2.setOffset({x: Math.floor(event.nativeEvent.absoluteX - c_initial_coordinate_left),y: Math.floor(event.nativeEvent.absoluteY - c_initial_coordinate_top),});
this.spaceAnimatedTranslations3.setOffset({x: Math.floor(event.nativeEvent.absoluteX - c_initial_coordinate_left),y: Math.floor(event.nativeEvent.absoluteY - c_initial_coordinate_top),});
this.spaceAnimatedTranslations4.setOffset({x: Math.floor(event.nativeEvent.absoluteX - c_initial_coordinate_left),y: Math.floor(event.nativeEvent.absoluteY - c_initial_coordinate_top),});
this.spaceAnimatedTranslations5.setOffset({x: Math.floor(event.nativeEvent.absoluteX - c_initial_coordinate_left),y: Math.floor(event.nativeEvent.absoluteY - c_initial_coordinate_top ),});
this.gestureStartedX = event.nativeEvent.absoluteX;
this.gestureStartedY = event.nativeEvent.absoluteY;
}
if (event.nativeEvent.state === State.END) {
this.onSpaceMove(event);
}
}
render() {
return (
<ImageBackground source={backImg} style={{ flex: 1 }}>
{this.debug_message ? (
<Text style={{ color: 'white' }}>{this.debug_message}</Text>
) : (
undefined
)}
<PanGestureHandler
key={`test`}
onGestureEvent={e => this.onSpaceMove(e)}
onHandlerStateChange={e => this.onSpaceMoveCompleted(e)}>
<Animated.View
ref={ref => {
this.testAnimatedView = ref;
}}
style={[styles._animatable_view, this._animatedStyle]}
useNativeDriver={true}>
<View style={styles._box_content}>
<Text
style={{
width: '100%',
height: '100%',
fontSize: 15,
textAlign: 'center',
textAlignVertical: 'center',
borderRadius: 20,
}}
editable={false}
ref={ref => {
this.textInputRef = ref;
}}
>
{'Master (1) (DRAG THIS ONE)'}
</Text>
</View>
</Animated.View>
</PanGestureHandler>
<Animated.View
ref={ref => {
this.testAnimatedView2 = ref;
}}
style={[styles._animatable_view2, this._animatedStyle2]}
useNativeDriver={true}>
<View style={styles._box_content}>
<Text
style={{
width: '100%',
height: '100%',
fontSize: 15,
textAlign: 'center',
textAlignVertical: 'center',
borderRadius: 20,
}}
editable={false}
ref={ref => {
this.textInputRef = ref;
}}
>
{'Slave (2) '}
</Text>
</View>
</Animated.View>
<Animated.View
ref={ref => {
this.testAnimatedView3 = ref;
}}
style={[styles._animatable_view3, this._animatedStyle3]}
useNativeDriver={true}>
<View style={styles._box_content}>
<Text
style={{
width: '100%',
height: '100%',
fontSize: 15,
textAlign: 'center',
textAlignVertical: 'center',
borderRadius: 20,
}}
editable={false}
ref={ref => {
this.textInputRef = ref;
}}
>
{'Slave (3) '}
</Text>
</View>
</Animated.View>
<Animated.View
ref={ref => {
this.testAnimatedView4 = ref;
}}
style={[styles._animatable_view4, this._animatedStyle4]}
useNativeDriver={true}>
<View style={styles._box_content}>
<Text
style={{
width: '100%',
height: '100%',
fontSize: 15,
textAlign: 'center',
textAlignVertical: 'center',
borderRadius: 20,
}}
editable={false}
ref={ref => {
this.textInputRef = ref;
}}
>
{'Slave (4) '}
</Text>
</View>
</Animated.View>
<Animated.View
ref={ref => {
this.testAnimatedView5 = ref;
}}
style={[styles._animatable_view5, this._animatedStyle5]}
useNativeDriver={true}>
<View style={styles._box_content}>
<Text
style={{
width: '100%',
height: '100%',
fontSize: 15,
textAlign: 'center',
textAlignVertical: 'center',
borderRadius: 20,
}}
editable={false}
ref={ref => {
this.textInputRef = ref;
}}
>
{'Slave (5) '}
</Text>
</View>
</Animated.View>
</ImageBackground>
);
}
}
const styles = StyleSheet.create({
_animatable_view: {
flex: 1,
width: 250,
height: 50,
top: c_initial_coordinate_top,
left: c_initial_coordinate_left,
position: 'absolute',
backgroundColor: '#ABC',
alignItems: 'center',
justifyContent: 'center',
borderColor: 'gainsboro',
borderWidth: 2,
},
_animatable_view2: {
flex: 1,
width: 250,
height: 50,
top: c_initial_coordinate_top + 100,
left: c_initial_coordinate_left,
position: 'absolute',
backgroundColor: '#ABC',
alignItems: 'center',
justifyContent: 'center',
borderColor: 'gainsboro',
borderWidth: 2,
},
_animatable_view3: {
flex: 1,
width: 250,
height: 50,
top: c_initial_coordinate_top + 200,
left: c_initial_coordinate_left,
position: 'absolute',
backgroundColor: '#ABC',
alignItems: 'center',
justifyContent: 'center',
borderColor: 'gainsboro',
borderWidth: 2,
},
_animatable_view4: {
flex: 1,
width: 250,
height: 50,
top: c_initial_coordinate_top + 300,
left: c_initial_coordinate_left,
position: 'absolute',
backgroundColor: '#ABC',
alignItems: 'center',
justifyContent: 'center',
borderColor: 'gainsboro',
borderWidth: 2,
},
_animatable_view5: {
flex: 1,
width: 250,
height: 50,
top: c_initial_coordinate_top + 400,
left: c_initial_coordinate_left,
position: 'absolute',
backgroundColor: '#ABC',
alignItems: 'center',
justifyContent: 'center',
borderColor: 'gainsboro',
borderWidth: 2,
},
_box_content: {
flex: 1,
height: '100%',
width: '100%',
borderRadius: Math.min(this.rectangleHeight, this.rectangleWidth) / 2,
alignItems: 'center',
justifyContent: 'center',
borderColor: 'gainsboro',
borderWidth: 2,
opacity: 0.9,
},
});
这可以在这个小吃中看到:https ://snack.expo.io/@mehmetkaplan/movetextwithgesturesingle
此外,为了感受性能问题,我生成了另一个零食,它简单地同时为 5 个对象设置动画。如果你通过低端安卓设备运行这个,你会感觉到性能问题:https ://snack.expo.io/@mehmetkaplan/movetextwithgesturemulti
解决方案
我还想补充一点, useNativeDriver不是您添加到组件的道具!useNativeDriver={true}
这里的用法绝对没有任何作用!从文档本身来看,useNativeDriver 的正确用法在Animated.[function]
s. 使用上面的代码,正确的用法将位于此处:
Animated.timing(this.spaceAnimatedTranslations5.x, {
toValue: event.nativeEvent.translationX,
duration: 0,
easing: Easing.linear
})
您需要将其添加为第二个参数中的另一个选项作为选项对象的属性。
Animated.timing([Animated Value], {options})
Animated.timing(this.spaceAnimatedTranslations5.x, {
toValue: event.nativeEvent.translationX,
duration: 0,
easing: Easing.linear,
useNativeDriver: true
})
您可以使用的其他动画功能是:Animated.event
或Animated.interpolate
。
动画的处理量很大,因此请确保useNativeDriver
尽可能使用任何适用的动画。
推荐阅读
- java - JDBC 根据另一个 select 语句的结果执行 select 语句
- php - 我正在尝试将数据传递到我的注册视图
- c# - C# 任务独立主线程
- bootstrap-4 - justify-content-around 用于轮播指标
- powershell - 可以忽略 VS Code 调试器中的代码行吗?
- c# - 如何在特定的 div 类中动态生成 texbox 或标签?
- asp.net-mvc - 在我的 DBContext 上,我收到一个错误,表明该实例已被跟踪。使用 nottracking 时会变得更糟
- html - 如何在html页面中以表格格式显示数据库表名
- php - 无法覆盖 Symfony 4 上 POST 请求中可选参数的默认值
- css - 显示:无;不工作但可见性:隐藏;做