REACT本机flatlist动画在RTL设备上无法正常工作
我在需要使用RTL设备的flatlist动画的应用程序中工作。我构建了一个小应用程序,以了解它将如何工作。当将应用与LTR设备一起使用时,它可以正常运行,当我使用i18nmanager.forcertl(true)时,一切都混乱了。
我有三个带有两个组件的幻灯片,第一个组件显示幻灯片本身,第二个组件显示了幻灯片的数量。
当应用强制RTL时,第一个组件从第一个幻灯片开始,但是第二个组件启动了最后一个!
当我使用两个动画(变换和不透明度)作为第一个组件的一个元素时。第一台幻灯片和最后一张幻灯片消失了!
这是我的代码,带有力rtl:
import React, { useRef } from "react";
import {
SafeAreaView,
View,
StyleSheet,
Text,
StatusBar,
Dimensions,
Animated,
} from "react-native";
import { I18nManager } from "react-native";
I18nManager.allowRTL(true);
I18nManager.forceRTL(true);
const { width, height } = Dimensions.get("window");
const DATA = [
{
id: "bd7acbea-c1b1-46c2-aed5-3ad53abb28ba",
title: "First Slide",
number: "1",
},
{
id: "3ac68afc-c605-48d3-a4f8-fbd91aa97f63",
title: "Second Slide",
number: "2",
},
{
id: "58694a0f-3da1-471f-bd96-145571e29d72",
title: "Third Slide",
number: "3",
},
];
const Item = ({ title, index, scrollX }) => {
const inputRange = [(index - 1) * width, index * width, (index + 1) * width];
const opacityInputRange = [
(index - 0.4) * width,
index * width,
(index + 0.4) * width,
];
const scale = scrollX.interpolate({
inputRange,
outputRange: [0, 1, 0],
});
const opacity = scrollX.interpolate({
inputRange: opacityInputRange,
outputRange: [0, 1, 0],
});
return (
<View style={styles.mainConatainer}>
<Animated.View
style={{
backgroundColor: "blue",
width: width / 1.6,
height: height / 3,
alignItems: "center",
justifyContent: "center",
borderRadius: width,
transform: [{ scale }],
opacity,
}}
>
<Animated.Text
style={{
fontSize: 32,
color: "white",
transform: [{ scale }],
}}
>
{title}
</Animated.Text>
</Animated.View>
</View>
);
};
const Footer = ({ scrollX }) => {
return (
<View>
{DATA.map(({ number }, index) => {
const inputRange = [
(index - 1) * width,
index * width,
(index + 1) * width,
];
const scale = scrollX.interpolate({
inputRange,
outputRange: [0, 1, 0],
});
return (
<Animated.View key={index} style={{ transform: [{ scale }] }}>
<Text
style={{
fontSize: 50,
alignItems: "center",
marginBottom: 50,
position: "absolute",
bottom: "40%",
right: "50%",
color: "blue",
}}
>
{number}
</Text>
</Animated.View>
);
})}
</View>
);
};
export default function App() {
const scrollX = useRef(new Animated.Value(0)).current;
return (
<SafeAreaView style={styles.container}>
<Animated.FlatList
data={DATA}
renderItem={({ item, index }) => (
<Item {...item} index={index} scrollX={scrollX} />
)}
keyExtractor={(item) => item.id}
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { x: scrollX } } }],
{ useNativeDriver: true }
)}
scrollEventThrottle={16}
inverted={true}
/>
<Footer scrollX={scrollX} />
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: StatusBar.currentHeight || 0,
backgroundColor: "lightgrey",
},
mainConatainer: {
width,
alignItems: "center",
justifyContent: "center",
},
item: {
backgroundColor: "blue",
width: width / 1.6,
height: height / 3,
alignItems: "center",
justifyContent: "center",
borderRadius: width,
},
title: {
fontSize: 64,
color: "white",
},
});
没有强制RTL:
import React, { useRef } from "react";
import {
SafeAreaView,
View,
StyleSheet,
Text,
StatusBar,
Dimensions,
Animated,
} from "react-native";
const { width, height } = Dimensions.get("window");
const DATA = [
{
id: "bd7acbea-c1b1-46c2-aed5-3ad53abb28ba",
title: "First Slide",
number: "1",
},
{
id: "3ac68afc-c605-48d3-a4f8-fbd91aa97f63",
title: "Second Slide",
number: "2",
},
{
id: "58694a0f-3da1-471f-bd96-145571e29d72",
title: "Third Slide",
number: "3",
},
];
const Item = ({ title, index, scrollX }) => {
const inputRange = [(index - 1) * width, index * width, (index + 1) * width];
const opacityInputRange = [
(index - 0.4) * width,
index * width,
(index + 0.4) * width,
];
const scale = scrollX.interpolate({
inputRange,
outputRange: [0, 1, 0],
});
const opacity = scrollX.interpolate({
inputRange: opacityInputRange,
outputRange: [0, 1, 0],
});
return (
<View style={styles.mainConatainer}>
<Animated.View
style={{
backgroundColor: "blue",
width: width / 1.6,
height: height / 3,
alignItems: "center",
justifyContent: "center",
borderRadius: width,
transform: [{ scale }],
opacity,
}}
>
<Animated.Text
style={{
fontSize: 32,
color: "white",
transform: [{ scale }],
}}
>
{title}
</Animated.Text>
</Animated.View>
</View>
);
};
const Footer = ({ scrollX }) => {
return (
<View>
{DATA.map(({ number }, index) => {
const inputRange = [
(index - 1) * width,
index * width,
(index + 1) * width,
];
const scale = scrollX.interpolate({
inputRange,
outputRange: [0, 1, 0],
});
return (
<Animated.View key={index} style={{ transform: [{ scale }] }}>
<Text
style={{
fontSize: 50,
alignItems: "center",
marginBottom: 50,
position: "absolute",
bottom: "40%",
right: "50%",
color: "blue",
}}
>
{number}
</Text>
</Animated.View>
);
})}
</View>
);
};
export default function App() {
const scrollX = useRef(new Animated.Value(0)).current;
return (
<SafeAreaView style={styles.container}>
<Animated.FlatList
data={DATA}
renderItem={({ item, index }) => (
<Item {...item} index={index} scrollX={scrollX} />
)}
keyExtractor={(item) => item.id}
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { x: scrollX } } }],
{ useNativeDriver: true }
)}
scrollEventThrottle={16}
inverted={true}
/>
<Footer scrollX={scrollX} />
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: StatusBar.currentHeight || 0,
backgroundColor: "lightgrey",
},
mainConatainer: {
width,
alignItems: "center",
justifyContent: "center",
},
item: {
backgroundColor: "blue",
width: width / 1.6,
height: height / 3,
alignItems: "center",
justifyContent: "center",
borderRadius: width,
},
title: {
fontSize: 64,
color: "white",
},
});
I'm working in app that needs flatlist animation with RTL devices. I built a small app to understand how it will work. When using the app with LTR devices, it works just fine, and when I use I18nManager.forceRTL(true) everything messed up.
I have three slides with two components, the first component shows the slide itself and the second shows the number of the slide.
When apply force RTL the first component starts with the first slide but the second component start form the last one!
Also, when I use two animations (transform and opacity) for one element of the first component. The first slide and the last slide disappeared!
Here is my code with force RTL:
import React, { useRef } from "react";
import {
SafeAreaView,
View,
StyleSheet,
Text,
StatusBar,
Dimensions,
Animated,
} from "react-native";
import { I18nManager } from "react-native";
I18nManager.allowRTL(true);
I18nManager.forceRTL(true);
const { width, height } = Dimensions.get("window");
const DATA = [
{
id: "bd7acbea-c1b1-46c2-aed5-3ad53abb28ba",
title: "First Slide",
number: "1",
},
{
id: "3ac68afc-c605-48d3-a4f8-fbd91aa97f63",
title: "Second Slide",
number: "2",
},
{
id: "58694a0f-3da1-471f-bd96-145571e29d72",
title: "Third Slide",
number: "3",
},
];
const Item = ({ title, index, scrollX }) => {
const inputRange = [(index - 1) * width, index * width, (index + 1) * width];
const opacityInputRange = [
(index - 0.4) * width,
index * width,
(index + 0.4) * width,
];
const scale = scrollX.interpolate({
inputRange,
outputRange: [0, 1, 0],
});
const opacity = scrollX.interpolate({
inputRange: opacityInputRange,
outputRange: [0, 1, 0],
});
return (
<View style={styles.mainConatainer}>
<Animated.View
style={{
backgroundColor: "blue",
width: width / 1.6,
height: height / 3,
alignItems: "center",
justifyContent: "center",
borderRadius: width,
transform: [{ scale }],
opacity,
}}
>
<Animated.Text
style={{
fontSize: 32,
color: "white",
transform: [{ scale }],
}}
>
{title}
</Animated.Text>
</Animated.View>
</View>
);
};
const Footer = ({ scrollX }) => {
return (
<View>
{DATA.map(({ number }, index) => {
const inputRange = [
(index - 1) * width,
index * width,
(index + 1) * width,
];
const scale = scrollX.interpolate({
inputRange,
outputRange: [0, 1, 0],
});
return (
<Animated.View key={index} style={{ transform: [{ scale }] }}>
<Text
style={{
fontSize: 50,
alignItems: "center",
marginBottom: 50,
position: "absolute",
bottom: "40%",
right: "50%",
color: "blue",
}}
>
{number}
</Text>
</Animated.View>
);
})}
</View>
);
};
export default function App() {
const scrollX = useRef(new Animated.Value(0)).current;
return (
<SafeAreaView style={styles.container}>
<Animated.FlatList
data={DATA}
renderItem={({ item, index }) => (
<Item {...item} index={index} scrollX={scrollX} />
)}
keyExtractor={(item) => item.id}
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { x: scrollX } } }],
{ useNativeDriver: true }
)}
scrollEventThrottle={16}
inverted={true}
/>
<Footer scrollX={scrollX} />
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: StatusBar.currentHeight || 0,
backgroundColor: "lightgrey",
},
mainConatainer: {
width,
alignItems: "center",
justifyContent: "center",
},
item: {
backgroundColor: "blue",
width: width / 1.6,
height: height / 3,
alignItems: "center",
justifyContent: "center",
borderRadius: width,
},
title: {
fontSize: 64,
color: "white",
},
});
Without force RTL:
import React, { useRef } from "react";
import {
SafeAreaView,
View,
StyleSheet,
Text,
StatusBar,
Dimensions,
Animated,
} from "react-native";
const { width, height } = Dimensions.get("window");
const DATA = [
{
id: "bd7acbea-c1b1-46c2-aed5-3ad53abb28ba",
title: "First Slide",
number: "1",
},
{
id: "3ac68afc-c605-48d3-a4f8-fbd91aa97f63",
title: "Second Slide",
number: "2",
},
{
id: "58694a0f-3da1-471f-bd96-145571e29d72",
title: "Third Slide",
number: "3",
},
];
const Item = ({ title, index, scrollX }) => {
const inputRange = [(index - 1) * width, index * width, (index + 1) * width];
const opacityInputRange = [
(index - 0.4) * width,
index * width,
(index + 0.4) * width,
];
const scale = scrollX.interpolate({
inputRange,
outputRange: [0, 1, 0],
});
const opacity = scrollX.interpolate({
inputRange: opacityInputRange,
outputRange: [0, 1, 0],
});
return (
<View style={styles.mainConatainer}>
<Animated.View
style={{
backgroundColor: "blue",
width: width / 1.6,
height: height / 3,
alignItems: "center",
justifyContent: "center",
borderRadius: width,
transform: [{ scale }],
opacity,
}}
>
<Animated.Text
style={{
fontSize: 32,
color: "white",
transform: [{ scale }],
}}
>
{title}
</Animated.Text>
</Animated.View>
</View>
);
};
const Footer = ({ scrollX }) => {
return (
<View>
{DATA.map(({ number }, index) => {
const inputRange = [
(index - 1) * width,
index * width,
(index + 1) * width,
];
const scale = scrollX.interpolate({
inputRange,
outputRange: [0, 1, 0],
});
return (
<Animated.View key={index} style={{ transform: [{ scale }] }}>
<Text
style={{
fontSize: 50,
alignItems: "center",
marginBottom: 50,
position: "absolute",
bottom: "40%",
right: "50%",
color: "blue",
}}
>
{number}
</Text>
</Animated.View>
);
})}
</View>
);
};
export default function App() {
const scrollX = useRef(new Animated.Value(0)).current;
return (
<SafeAreaView style={styles.container}>
<Animated.FlatList
data={DATA}
renderItem={({ item, index }) => (
<Item {...item} index={index} scrollX={scrollX} />
)}
keyExtractor={(item) => item.id}
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { x: scrollX } } }],
{ useNativeDriver: true }
)}
scrollEventThrottle={16}
inverted={true}
/>
<Footer scrollX={scrollX} />
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: StatusBar.currentHeight || 0,
backgroundColor: "lightgrey",
},
mainConatainer: {
width,
alignItems: "center",
justifyContent: "center",
},
item: {
backgroundColor: "blue",
width: width / 1.6,
height: height / 3,
alignItems: "center",
justifyContent: "center",
borderRadius: width,
},
title: {
fontSize: 64,
color: "white",
},
});
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论