React Native安装Moti等依赖后Android模拟器异常求助
Android模拟器中Moti/Reanimated组件UI异常问题
安装Moti、react-native-reanimated和react-native-gesture-handler后,仅Android模拟器出现UI异常(组件排版错乱、元素重叠),iPhone设备运行完全正常,控制台无任何错误输出。

相关代码
import { View, ScrollView } from "react-native"; import * as React from "react"; import { Avatar, Button, Card, Text, SegmentedButtons, Portal, Dialog, ActivityIndicator, HelperText, } from "react-native-paper"; import Slider from "@react-native-community/slider"; import { MotiView } from "moti"; const Generator = () => { const [amount, setAmount] = React.useState(0); const [mint, setMint] = React.useState(0); const [customMint, setCustomMint] = React.useState(5); const [type, setType] = React.useState([]); const [nicotine, setNicotine] = React.useState(""); const [visible, setVisible] = React.useState(false); const [genVisible, setGenVisible] = React.useState(false); const hideDialog = () => setVisible(false); function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } const genMix = async () => { setVisible(false); setGenVisible(true); await sleep(3500); setGenVisible(false); }; return ( <ScrollView> <View style={{ paddingVertical: 0 }}> <Card mode="contained" style={{ backgroundColor: "#F4F4F4", paddingBottom: 10 }} theme={{ roundness: 0 }} > <Card.Title title="Mix Generator" left={(props) => <Avatar.Icon {...props} icon="chip" />} /> <Card.Content> <MotiView from={{ opacity: 0, scale: 0.5, translateY: 30 }} animate={{ opacity: 1, scale: 1, translateY: 0 }} transition={{ type: "spring" }} > <Text variant="titleMedium" style={{ marginBottom: 6 }}> How many flavors woud you like to mix? </Text> <SegmentedButtons theme={{ roundness: 1 }} value={amount} onValueChange={setAmount} buttons={[ { value: "2", label: "2", }, { value: "3", label: "3", }, { value: "4", label: "4", }, { value: "5", label: "5" }, ]} /> </MotiView> {amount !== 0 && ( <MotiView from={{ opacity: 0, scale: 0.5, translateY: 30 }} animate={{ opacity: 1, scale: 1, translateY: 0 }} transition={{ type: "spring" }} > <Text variant="titleMedium" style={{ marginVertical: 6 }}> Would you like to add mint? </Text> <SegmentedButtons theme={{ roundness: 1 }} value={mint} onValueChange={setMint} buttons={[ { value: "nomint", label: "No mint", }, { value: "10", label: "10%", }, { value: "20", label: "20%", }, { value: "custom", label: "Custom" }, ]} /> </MotiView> )} {mint === "custom" && ( <MotiView style={{ padding: 10 }} from={{ opacity: 0, scale: 0.5, translateY: 30 }} animate={{ opacity: 1, scale: 1, translateY: 0 }} transition={{ type: "spring" }} > <HelperText type="info" style={{ fontSize: 17, color: "#424242", marginTop: 12, textAlign: "center", }} > Mint amount: {customMint}% </HelperText> <Slider style={{ height: 40, alignItems: "center", marginVertical: 6, }} lowerLimit={0.05} step={0.05} minimumValue={0.05} maximumValue={0.8} minimumTrackTintColor="#663399" maximumTrackTintColor="#CCCCCC" thumbTintColor="#663399" value={0.05} onValueChange={(value) => setCustomMint(parseInt(value * 100)) } /> <Button theme={{ roundness: 1 }} icon="leaf-circle" mode="elevated" onPress={() => setMint(customMint)} style={{ marginHorizontal: 20 }} > Set </Button> </MotiView> )} {mint !== 0 && ( <MotiView from={{ opacity: 0, scale: 0.5, translateY: 30 }} animate={{ opacity: 1, scale: 1, translateY: 0 }} transition={{ type: "spring" }} > <Text variant="titleMedium" style={{ marginVertical: 6 }}> What flavor profile would you like? </Text> <SegmentedButtons multiSelect theme={{ roundness: 1 }} value={type} onValueChange={setType} buttons={[ { value: "fruity", label: "Fruit", }, { value: "citrus", label: "Citrus", }, { value: "desert", label: "Desert", }, { value: "floral", label: "Floral" }, ]} /> {type.length !== 2 && ( <HelperText type="info" style={{ fontSize: 15, color: "#787878", marginTop: 6, textAlign: "center", }} > Select up to 2 </HelperText> )} </MotiView> )} {type.length !== 0 && ( <MotiView from={{ opacity: 0, scale: 0.5, translateY: 30 }} animate={{ opacity: 1, scale: 1, translateY: 0 }} transition={{ type: "spring" }} > <Text variant="titleMedium" style={{ marginVertical: 6 }}> Nicotine level? </Text> <SegmentedButtons theme={{ roundness: 1 }} value={nicotine} onValueChange={setNicotine} buttons={[ { value: "low", label: "Low", }, { value: "medium", label: "Medium", }, { value: "high", label: "High", }, ]} /> </MotiView> )} </Card.Content> {nicotine !== "" && ( <MotiView style={{ alignItems: "center" }} from={{ opacity: 0, scale: 0.5, translateY: 30 }} animate={{ opacity: 1, scale: 1, translateY: 0 }} transition={{ type: 'spring' }} > <Button mode="contained" icon="fire" theme={{ roundness: 0 }} style={{ marginTop: 50, marginBottom: 10, width: "70%" }} onPress={() => setVisible(true)} > Generate Mix </Button> </MotiView> )} <Portal> <Dialog visible={visible} onDismiss={hideDialog} theme={{ roundness: 2 }} > <Dialog.Icon icon="leaf" /> <Dialog.Title style={{ textAlign: "center" }}> Mix Overview </Dialog.Title> <Dialog.Content> <Text variant="bodyLarge">Amount of Flavors: {amount}</Text> <Text variant="bodyLarge">Mint: {mint}%</Text> <Text variant="bodyLarge"> Flavor Profile:{" "} {type.map((item) => ( <Text key={item}> {item.toUpperCase()}</Text> ))} </Text> <Text variant="bodyLarge"> Nicotine Preference: {nicotine.toUpperCase()} </Text> <Button theme={{ roundness: 1 }} icon="pencil" mode="outlined" onPress={hideDialog} style={{ marginVertical: 10, marginTop: 30 }} > Edit </Button> <Button theme={{ roundness: 1 }} icon="apache-kafka" mode="contained" onPress={genMix} > Generate Mix </Button> </Dialog.Content> </Dialog> <Dialog visible={genVisible} theme={{ roundness: 2 }} dismissable={false} > <Dialog.Icon icon="leaf" /> <Dialog.Title style={{ textAlign: "center" }}> Generating Mix... </Dialog.Title> <Dialog.Content> <ActivityIndicator animating={true} size={25} style={{ marginTop: 10 }} /> </Dialog.Content> </Dialog> </Portal> </Card> </View> </ScrollView> ); }; export default Generator;
已尝试的无效方案
- 查阅StackOverflow及Google相关解决方案,未找到匹配案例
- 修改babel配置文件(添加Reanimated插件)
- 在主App.js中提前导入
react-native-reanimated和react-native-gesture-handler
可行解决方案建议
确保Reanimated的Android配置完整
- 打开
android/app/build.gradle,确认enableHermes已设为true:project.ext.react = [ enableHermes: true ] - 执行
cd android && ./gradlew clean清理缓存,再重新编译项目。
- 打开
关闭Android模拟器硬件加速
- 启动模拟器后,进入设置 → 高级 → 关闭"使用硬件加速图形"
- 或通过命令行启动:
emulator -avd [你的模拟器名称] -gpu off
升级依赖并重新初始化Reanimated
- 安装最新稳定版依赖:
npm install moti@latest react-native-reanimated@latest react-native-gesture-handler@latest - 运行Reanimated初始化脚本:
npx react-native-reanimated-init
- 安装最新稳定版依赖:
调整MotiView动画类型
- 将spring动画替换为timing动画,避免Android环境兼容性问题:
transition={{ type: 'timing', duration: 300 }} - 或临时移除
scale属性,测试仅opacity和translateY动画是否正常。
- 将spring动画替换为timing动画,避免Android环境兼容性问题:
排查React Native Paper主题冲突
- 移除Card、SegmentedButtons等组件的
theme配置,确认是否是主题样式与Moti动画的冲突。
- 移除Card、SegmentedButtons等组件的
内容的提问来源于stack exchange,提问作者Tony Chronic
相关产品推荐
相关产品推荐

