我有以下代码来创建“动态”文本输入。标签放置在文本输入上方。当 textinput 获得焦点时,标签会移动到 textinput 上方,并且字体大小和颜色会发生变化。在 textinput 模糊时,标签会向后移动(如果 textinput 中没有输入)。
此代码包含react-native-reanimated
代码,动画应该在 UI 线程而不是 JS 线程上工作。
当我在 IOS 模拟器(测试 iPhone 7 -> iPhone 11 Pro)上测试此代码并专注于文本输入以便动画运行时,JS 线程下降了大约 3-6 帧(54-57 fps),这没关系我猜测。在真实设备(iPhone 7)上,JS 线程丢帧大约 20-30 帧(有时甚至更多)。当我开始输入 textinput 时,我得到一个缓慢的回调(我在输入时检查 textinput 的输入)。在模拟器上,回调是立即的。在真实设备上,有时最多需要 2 秒才能检查输入。
import React, { useState, useEffect } from 'react';
import { View, TextInput } from 'react-native';
import Animated, { Easing, Extrapolate } from 'react-native-reanimated';
import { interpolateColor, useTimingTransition } from 'react-native-redash';
import Colors from '../../constants/Colors';
const { interpolate } = Animated;
const AuthenticationInput = React.forwardRef((props, ref) => {
const {
ref,
label,
onChangeText,
secureTextEntry,
returnKeyType,
icon
} = props;
const [value, setValue] = useState('');
const [trans, setTrans] = useState(0);
const transition = useTimingTransition(trans, {
duration: 250,
easing: Easing.inOut(Easing.ease)
});
// move the label in the x direction
const moveX = interpolate(transition, {
inputRange: [0, 1],
outputRange: [12.5, 0],
extrapolate: Extrapolate.CLAMP
});
// move the label in the y direction
const moveY = interpolate(transition, {
inputRange: [0, 1],
outputRange: [12.5, -20],
extrapolate: Extrapolate.CLAMP
});
// change the font size of the label
const fontSize = interpolate(transition, {
inputRange: [0, 1],
outputRange: [15, 12.5],
extrapolate: Extrapolate.CLAMP
});
// change the color of the label
const color = interpolateColor(transition, {
inputRange: [0, 1],
outputRange: ['#aaa', '#000']
});
// pass the input of the textinput to the
// onChangeText function passed as a prop
useEffect(() => {
onChangeText(value)
}, [value]);
return (
<View style={{
marginHorizontal: 25,
marginTop: 25,
borderRadius: 5,
backgroundColor: Colors.white
}}
>
<Animated.View style={{
position: 'absolute',
transform: [{ translateX: moveX }, { translateY: moveY }]
}}
>
<Animated.Text style={{
fontSize,
color
}}
>
{label}
</Animated.Text>
</Animated.View>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<TextInput
ref={ref}
autoCapitalize="none"
autoCompleteType="off"
autoCorrect={false}
secureTextEntry={secureTextEntry}
onChangeText={(v) => setValue(v)}
style={{
margin: 0,
padding: 12.5,
flex: 1,
fontSize: 15
}}
hitSlop={{
top: 10,
right: 10,
bottom: 10,
left: 10
}}
onFocus={() => setTrans(1)}
onBlur={() => {
if (value.length === 0) {
setTrans(0);
}
}}
returnKeyType={returnKeyType}
/>
<View style={{ padding: 12.5 }}>
{icon}
</View>
</View>
</View>
);
});
export default AuthenticationInput;