我正在尝试使用 react-native 的 Animated 将 react 组件移植到 React-Native
我设法创建了圆圈,它的轨道和工作良好。
但我不知道如何在 react-native 的 Animated 中编写这些规则
在@keyframes fulfilling-bouncing-circle-spinner-orbit-animation
我需要等到动画的一半然后我应该把它缩小和放大两次
并且在@keyframes fulfilling-bouncing-circle-spinner-circle-animation
我不知道如何使用反应原生动画添加和删除样式时,一直在思考它,但我没有想出一个主意。
那么有没有一种方法可以添加时间序列并在这些帧中执行我想要的操作,就像@keyframes 一样。
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
const BouncingCircle = styled.div`
height: ${props => props.size}px;
width: ${props => props.size}px;
position: relative;
animation: fulfilling-bouncing-circle-spinner-animation infinite
${props => props.animationDuration}ms ease;
* {
box-sizing: border-box;
}
.orbit {
height: ${props => props.size}px;
width: ${props => props.size}px;
position: absolute;
top: 0;
left: 0;
border-radius: 50%;
border: calc(${props => props.size}px * 0.03) solid ${props => props.color};
animation: fulfilling-bouncing-circle-spinner-orbit-animation infinite
${props => props.animationDuration}ms ease;
}
.circle {
height: ${props => props.size}px;
width: ${props => props.size}px;
color: ${props => props.color};
display: block;
border-radius: 50%;
position: relative;
border: calc(${props => props.size}px * 0.1) solid ${props => props.color};
animation: fulfilling-bouncing-circle-spinner-circle-animation infinite
${props => props.animationDuration}ms ease;
transform: rotate(0deg) scale(1);
}
@keyframes fulfilling-bouncing-circle-spinner-animation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes fulfilling-bouncing-circle-spinner-orbit-animation {
0% {
transform: scale(1);
}
50% {
transform: scale(1);
}
62.5% {
transform: scale(0.8);
}
75% {
transform: scale(1);
}
87.5% {
transform: scale(0.8);
}
100% {
transform: scale(1);
}
}
@keyframes fulfilling-bouncing-circle-spinner-circle-animation {
0% {
transform: scale(1);
border-color: transparent;
border-top-color: inherit;
}
16.7% {
border-color: transparent;
border-top-color: initial;
border-right-color: initial;
}
33.4% {
border-color: transparent;
border-top-color: inherit;
border-right-color: inherit;
border-bottom-color: inherit;
}
50% {
border-color: inherit;
transform: scale(1);
}
62.5% {
border-color: inherit;
transform: scale(1.4);
}
75% {
border-color: inherit;
transform: scale(1);
opacity: 1;
}
87.5% {
border-color: inherit;
transform: scale(1.4);
}
100% {
border-color: transparent;
border-top-color: inherit;
transform: scale(1);
}
}
`;
const propTypes = {
size: PropTypes.number,
animationDuration: PropTypes.number,
color: PropTypes.string,
className: PropTypes.string,
style: PropTypes.object,
};
const defaultProps = {
size: 60,
color: '#fff',
animationDuration: 4000,
className: '',
};
const FulfillingBouncingCircleSpinner = ({
size,
color,
animationDuration,
className,
style,
...props
}) => (
<BouncingCircle
size={size}
color={color}
animationDuration={animationDuration}
className={`fulfilling-bouncing-circle-spinner${
className ? ' ' + className : ''
}`}
style={style}
{...props}
>
<div className="circle" />
<div className="orbit" />
</BouncingCircle>
);
FulfillingBouncingCircleSpinner.propTypes = propTypes;
FulfillingBouncingCircleSpinner.defaultProps = defaultProps;
export default FulfillingBouncingCircleSpinner;
/** @flow **/
import React, { useEffect, useState } from 'react';
import type { ViewStyleProp } from 'react-native/Libraries/StyleSheet/StyleSheet';
import { Animated, Easing, StyleSheet } from 'react-native';
import { AnimationUtils } from '../animationUtils';
type EpicProps = {
size?: number,
duration?: number,
color?: string,
style?: ViewStyleProp
};
const EpicDefaultProps = {
size: 200,
color: 'red',
duration: 1000
};
export const FulfillingBouncingCircleSpinner = ({ size, color, duration, style, ...props }: EpicProps) => {
const [animate] = useState(new Animated.Value(0));
const spinnerStyle = StyleSheet.create({
container: {
height: size,
width: size,
position: 'relative'
},
circle: {
height: size,
width: size,
borderColor: color,
borderRadius: size * 0.5,
position: 'relative',
borderWidth: size * 0.1
},
orbit: {
height: size,
width: size,
position: 'absolute',
top: 0,
left: 0,
borderColor: color,
borderRadius: size * 0.5,
borderWidth: size * 0.03
}
});
const containerRotation = AnimationUtils.interpolation(animate, [0, 1], ['0deg', '360deg']);
const circle = AnimationUtils.interpolation(animate, [0, 1], [1, 1.4]);
const orbit = AnimationUtils.interpolation(animate, [0, 1], [1, 0.8]);
useEffect(() => {
Animated.loop(
Animated.sequence([
Animated.timing(animate, { toValue: 1, duration: duration, useNativeDriver: true, easing: Easing.back() }),
Animated.timing(animate, { toValue: 0, duration: duration, useNativeDriver: true, easing: Easing.back() })
])
).start();
}, [animate, duration]);
return (
<Animated.View style={[style, spinnerStyle.container, { transform: [{ rotate: containerRotation }] }]} {...props}>
<Animated.View style={[spinnerStyle.circle, { transform: [{ scaleX: circle }, { scaleY: circle }] }]} />
<Animated.View style={[spinnerStyle.orbit, { transform: [{ scaleX: orbit }, { scaleY: orbit }] }]} />
</Animated.View>
);
};
FulfillingBouncingCircleSpinner.defaultProps = EpicDefaultProps;