react-native使用动画Animated

官方网文档:动画,Animated
一些精彩的例子:React Native 动画(Animated)
渐变组件的使用:ReactNative 进阶(四十五):渐变组件 react-native-linear-gradient

需要实现如下的动画动画效果:

shinebutton

进行拆分:

  • 亮光从左到右位置的移动 ==〉可以用marginLeft的值改变来展示 ==〉使用react-native的Animated方法
  • 当亮光移动到按钮的最右边的时候,透明度应该为0
  • 亮光是一个倾斜状的渐变白色块状 ===〉使用react-native-linear-gradient组件,包含对颜色的透明度

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(); // 开始执行动画
  • interpolate函数,可以将动画值从一个范围映射到另一个范围。

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',
  },
});

你可能感兴趣的:(react,native,react.js,javascript)