官方网文档:动画,Animated
一些精彩的例子:React Native 动画(Animated)
渐变组件的使用:ReactNative 进阶(四十五):渐变组件 react-native-linear-gradient
需要实现如下的动画动画效果:
shinebutton
进行拆分:
react-native的Animated方法:
const animatedValue = React.useRef(new Animated.Value(0)).current; // 创建value
const marginLeft = animatedValue.interpolate({
inputRange: [0, 1], // 当animatedValue的值从0变化到1的时候
outputRange: [0, 300], // marginLeft则从0变化到300
});
// opacity will be 0 if the shine view removed right
const opacity = animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [1, 0], // 透明度变化
extrapolate: 'clamp',
});
const rotateAnimated = Animated.timing(animatedValue, { // 必有,时间序列变化函数
toValue: 1, // 最终值
duration: 500, // 动画的持续时间(毫秒)
easing: Easing.in, // 缓动函数
});
rotateAnimated.start(); // 开始执行动画
react-native-linear-gradient组件:
<LinearGradient
start={{ x: 0, y: 0.2 }}
end={{ x: 0.8, y: 1 }}
colors={['rgba(255, 255, 255, 0)', 'rgba(255, 255, 255, 0.5)', 'rgba(255, 255, 255, 0)']}
style={[styles.shadowView, { width: height }]}
/>
完整代码:
import React, { memo, useEffect } from 'react';
import {
Animated,
Easing,
StyleSheet,
Text,
TextStyle,
TouchableWithoutFeedback,
View,
ViewStyle,
} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
export interface ShineButtonProps {
buttonText: string;
buttonTextStyle?: TextStyle;
buttonViewStyle: ViewStyle & { width: number; height: number }; // width and height are required
onPress: () => void;
}
const ShineButton = ({
buttonText,
buttonTextStyle,
buttonViewStyle,
onPress,
}: ShineButtonProps) => {
const { width, height } = buttonViewStyle;
const animatedValue = React.useRef(new Animated.Value(0)).current;
const marginLeft = animatedValue.interpolate({ // 映射函数
inputRange: [0, 1],
outputRange: [0, width],
});
// opacity will be 0 if the shine view removed right
const opacity = animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [1, 0],
extrapolate: 'clamp',
});
const rotateAnimated = Animated.timing(animatedValue, { // 必有,时间变化函数
toValue: 1,
duration: 500,
easing: Easing.in,
});
useEffect(() => {
rotateAnimated.start(); // 开始执行动画
});
return (
<View style={styles.viewContainer}>
<TouchableWithoutFeedback
style={styles.buttonContainer}
onPress={onPress}
>
<View style={[styles.buttonView, buttonViewStyle]}>
<Text style={[styles.buttonText, buttonTextStyle]}>{buttonText}</Text>
</View>
</TouchableWithoutFeedback>
<Animated.View
style={[
styles.animatedContainer,
{
marginLeft, // 使用
width: height,
height,
opacity,
},
]}
>
<LinearGradient
start={{ x: 0, y: 0.2 }}
end={{ x: 0.8, y: 1 }}
colors={['rgba(255, 255, 255, 0)', 'rgba(255, 255, 255, 0.5)', 'rgba(255, 255, 255, 0)']}
style={[styles.shadowView, { width: height }]}
/>
</Animated.View>
</View>
);
};
export default memo(ShineButton);
const styles = StyleSheet.create({
viewContainer: {
flex: 1,
position: 'relative',
},
buttonContainer: {
zIndex: 2,
},
animatedContainer: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
zIndex: 1,
},
shadowView: {
position: 'absolute',
top: 0,
bottom: 0,
},
buttonView: {
backgroundColor: Colors.white,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
},
buttonText: {
color: Colors.primary,
...TypographyFontPreset.R14,
fontWeight: '900',
},
});