Expo构建的React Native APK在OnePlus 5T上字符串末尾内容缺失
字符串显示截断问题(OnePlus 5T设备,React Native + NativeBase)
我用React Native开发的注册页面,通过eas build -p android --profile preview生成Android预览版APK。在Pixel 5模拟器上运行正常,但安装到OnePlus 5T设备后,部分字符串显示不完整:
- 'Username'显示为'Usernam',末尾'e'缺失
- 'Password'显示为'Passwor',末尾'd'缺失
- 'Login here.'显示为'Login',末尾'here.'缺失
试过在字符串后加空格或{" "},Expo Go模拟器里偶尔能解决,但APK版本完全无效。相关代码如下:
1. RegisterScreen.tsx
import { Text } from '@components'; import { useAlertToast } from '@hooks'; import { useNavigation } from '@react-navigation/native'; import { setAuthState, useRegisterMutation } from '@store'; import { Button, Center, FormControl, Input, Link, Stack, WarningOutlineIcon } from 'native-base'; import React, { useCallback, useEffect, useState } from 'react'; import { Controller, useForm } from 'react-hook-form'; import { KeyboardAvoidingView, StyleSheet } from 'react-native'; import { useDispatch } from 'react-redux'; import { StackNavProps } from 'StackNavigation'; import { saveEntryAsJson } from '../../utils/AsyncStorage'; import { Screens } from '../../utils/constants'; type RegisterationForm = { name: string; email: string; password: string; }; export const Register = () => { const { control, handleSubmit, formState: { errors }, } = useForm<RegisterationForm, any>({ defaultValues: { name: "", email: "", password: "", }, }); const { navigate } = useNavigation<StackNavProps>(); const [register, registerResult] = useRegisterMutation(); const { showErrorToast } = useAlertToast(); const dispath = useDispatch(); useEffect(() => { if (registerResult.isSuccess) { saveEntryAsJson("userData", registerResult.data); dispath(setAuthState(registerResult.data)); navigate(Screens.VERIFY_OTP); } else if (registerResult.isError) { //@ts-ignore showErrorToast(registerResult.error.data.message); } }, [registerResult.isSuccess]); const onSubmit = useCallback(async (data: RegisterationForm) => { await register({ ...data, }).unwrap(); }, []); return ( <KeyboardAvoidingView style={styles.container}> <Center style={styles.innerContainer}> <FormControl isInvalid={!!errors.name} marginY={3}> <Stack mx="4"> <FormControl.Label> <Text style={styles.inputLabel}>Username </Text> </FormControl.Label> <Controller control={control} rules={{ required: true, }} render={({ field: { onChange, onBlur, value } }) => ( <Input onBlur={onBlur} onChangeText={onChange} value={value} placeholder="Enter user name" /> )} name="name" /> {errors.name?.type === "required" && ( <FormControl.ErrorMessage leftIcon={<WarningOutlineIcon size="xs" />} > User name is required </FormControl.ErrorMessage> )} </Stack> </FormControl> <FormControl isInvalid={!!errors.email} marginY={3}> <Stack mx="4"> <FormControl.Label> <Text style={styles.inputLabel}>Email </Text> </FormControl.Label> <Controller control={control} rules={{ required: true, // pattern: RegExp("/^w+([.-]?w+)*@w+([.-]?w+)*(.ww+)+$/"), }} render={({ field: { onChange, onBlur, value } }) => ( <Input onBlur={onBlur} onChangeText={onChange} value={value} placeholder="Enter email address" keyboardType="email-address" /> )} name="email" /> {errors.email?.type === "pattern" && ( <FormControl.ErrorMessage leftIcon={<WarningOutlineIcon size="xs" />} > Invalid email address </FormControl.ErrorMessage> )} {errors.email?.type === "required" && ( <FormControl.ErrorMessage leftIcon={<WarningOutlineIcon size="xs" />} > Email address required </FormControl.ErrorMessage> )} </Stack> </FormControl> <FormControl isInvalid={!!errors.password} marginY={3}> <Stack mx="4"> <FormControl.Label> <Text style={styles.inputLabel}>Password</Text> </FormControl.Label> <Controller control={control} rules={{ required: true, minLength: 8, }} render={({ field: { onChange, onBlur, value } }) => ( <Input onBlur={onBlur} onChangeText={onChange} value={value} placeholder="Enter password" type="password" /> )} name="password" /> {errors.password?.type === "minLength" && ( <FormControl.ErrorMessage leftIcon={<WarningOutlineIcon size="xs" />} > Atleast 8 characters are required. </FormControl.ErrorMessage> )} {errors.password?.type === "required" && ( <FormControl.ErrorMessage leftIcon={<WarningOutlineIcon size="xs" />} > Password required. </FormControl.ErrorMessage> )} </Stack> </FormControl> <Button colorScheme={"orange"} style={styles.registerButton} onPress={handleSubmit(onSubmit)} > {"Register "} </Button> <Link style={styles.otherLink} onPress={() => navigate(Screens.LOGIN)}> <Text>Already registered?. Login here.</Text> </Link> </Center> </KeyboardAvoidingView> ); }; const styles = StyleSheet.create({ container: { flex: 1, }, inputLabel: { fontWeight: "700", color: "black", }, innerContainer: { flex: 1, paddingHorizontal: 5, }, registerButton: { borderRadius: 5, padding: 5, marginTop: 20, }, otherLink: { marginTop: 10, }, });
2. Text Component
import { ITextProps, Text as NativeText } from 'native-base'; export const Text = ({ children, ...rest }: ITextProps) => { return ( <NativeText _light={{ color: "black" }} _dark={{ color: "white" }} {...rest} > {children} </NativeText> ); };
解决思路及方案
1. 调整Label/Text组件的布局约束
NativeBase的FormControl.Label在部分设备上可能存在宽度计算不足的问题,导致文本被截断。可以给Label或内部Text添加样式:
// 给FormControl.Label添加右侧内边距 <FormControl.Label style={{ paddingRight: 8 }}> <Text style={styles.inputLabel}>Username</Text> </FormControl.Label> // 或者给Text添加flexShrink:0,禁止文本压缩 <Text style={{ ...styles.inputLabel, flexShrink: 0 }}>Username</Text>
2. 临时替换自定义Text组件
自定义Text组件的默认样式可能和NativeBase的Label存在冲突,暂时改用原生NativeBase Text测试:
// 替换import语句 import { Text } from 'native-base';
如果问题消失,说明自定义Text的_light/_dark配置影响了布局,需要调整样式优先级。
3. 关闭OnePlus设备的自适应字体缩放
OnePlus系统默认的文字缩放优化可能强制截断文本,在设备设置中操作:
- 打开「设置」→「显示」→「字体大小与显示」
- 关闭「自适应字体缩放」选项,重启应用查看效果
4. 添加零宽空格强制保留文本
在文本末尾添加零宽空格(\u200B)或不换行空格(\u00A0),避免被截断:
<Text style={styles.inputLabel}>Username\u200B</Text> <Text>Already registered?. Login here.\u00A0</Text>
5. 禁用打包时的资源压缩
EAS Build的资源压缩可能导致字符丢失,在eas.json的preview配置中添加:
"preview": { "android": { "buildType": "apk", "extraParams": { "android.enableResourceOptimizations": false } } }
内容的提问来源于stack exchange,提问作者Atharva Kalsekar
相关产品推荐
相关产品推荐

