React-native 动画时间序列及其百分比或替代方案
React-native animation time series with percentage or alternative for it
我正在尝试使用 react-native 的 Animated
将 react 组件移植到 React-Native
我设法创建了圆圈,它的轨道运行良好。
但我不知道如何在 react-native 的 Animated 中编写这些规则
在@keyframes fulfilling-bouncing-circle-spinner-orbit-animation
我需要等到动画的一半然后我应该缩小和放大两次
并且在@keyframes fulfilling-bouncing-circle-spinner-circle-animation
我不知道如何使用react native animation添加和删除样式,一直在想,但我没有想出一个主意。
那么有没有一种方法可以添加时间序列并以相同的方式在这些帧中执行我想要的操作
@关键帧有效。
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;
我花了一些时间在 React 动画文档上,我想出了一个解决方案,如果有人感兴趣或可以改进它,我将不胜感激。
/** @flow **/
import React, { useEffect, useState } from 'react';
import type { ViewStyleProp } from 'react-native/Libraries/StyleSheet/StyleSheet';
import { Animated, Easing, StyleSheet } from 'react-native';
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,
borderColor: color,
position: 'absolute',
top: 0,
left: 0,
borderRadius: size * 0.5,
borderWidth: size * 0.03
}
});
const animateStyle = {
container: {
transform: [
{
rotate: animate.interpolate({
inputRange: [0, 9, 10],
outputRange: ['0deg', '360deg', '360deg']
})
}
]
},
orbit: {
transform: [
{
scale: animate.interpolate({
inputRange: [0, 6, 7, 8, 9, 10],
outputRange: [1, 1, 0.8, 1, 0.8, 1]
})
}
]
},
circle: {
transform: [
{
scale: animate.interpolate({
inputRange: [0, 6, 7, 8, 9, 10],
outputRange: [1, 1, 1.4, 1, 1.4, 1]
})
}
],
borderColor: animate.interpolate({
inputRange: [0, 4, 5, 9, 10],
outputRange: ['transparent', 'transparent', color, color, 'transparent']
}),
borderTopColor: animate.interpolate({
inputRange: [0, 10],
outputRange: [color, color]
}),
borderRightColor: animate.interpolate({
inputRange: [0, 1, 2, 9, 10],
outputRange: ['transparent', 'transparent', color, color, 'transparent']
}),
borderBottomColor: animate.interpolate({
inputRange: [0, 2, 3, 9, 10],
outputRange: ['transparent', 'transparent', color, color, 'transparent']
})
}
};
useEffect(() => {
Animated.loop(
Animated.timing(animate, {
toValue: 10,
duration: duration * 4,
easing: Easing.inOut(Easing.ease)
})
).start();
}, [animate, duration]);
return (
<Animated.View style={[style, spinnerStyle.container, animateStyle.container]} {...props}>
<Animated.View style={[spinnerStyle.circle, animateStyle.circle]} />
<Animated.View style={[spinnerStyle.orbit, animateStyle.orbit]} />
</Animated.View>
);
};
FulfillingBouncingCircleSpinner.defaultProps = EpicDefaultProps;
我正在尝试使用 react-native 的 Animated
将 react 组件移植到 React-Native我设法创建了圆圈,它的轨道运行良好。
但我不知道如何在 react-native 的 Animated 中编写这些规则
在@keyframes fulfilling-bouncing-circle-spinner-orbit-animation
我需要等到动画的一半然后我应该缩小和放大两次
并且在@keyframes fulfilling-bouncing-circle-spinner-circle-animation
我不知道如何使用react native animation添加和删除样式,一直在想,但我没有想出一个主意。
那么有没有一种方法可以添加时间序列并以相同的方式在这些帧中执行我想要的操作 @关键帧有效。
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;
我花了一些时间在 React 动画文档上,我想出了一个解决方案,如果有人感兴趣或可以改进它,我将不胜感激。
/** @flow **/
import React, { useEffect, useState } from 'react';
import type { ViewStyleProp } from 'react-native/Libraries/StyleSheet/StyleSheet';
import { Animated, Easing, StyleSheet } from 'react-native';
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,
borderColor: color,
position: 'absolute',
top: 0,
left: 0,
borderRadius: size * 0.5,
borderWidth: size * 0.03
}
});
const animateStyle = {
container: {
transform: [
{
rotate: animate.interpolate({
inputRange: [0, 9, 10],
outputRange: ['0deg', '360deg', '360deg']
})
}
]
},
orbit: {
transform: [
{
scale: animate.interpolate({
inputRange: [0, 6, 7, 8, 9, 10],
outputRange: [1, 1, 0.8, 1, 0.8, 1]
})
}
]
},
circle: {
transform: [
{
scale: animate.interpolate({
inputRange: [0, 6, 7, 8, 9, 10],
outputRange: [1, 1, 1.4, 1, 1.4, 1]
})
}
],
borderColor: animate.interpolate({
inputRange: [0, 4, 5, 9, 10],
outputRange: ['transparent', 'transparent', color, color, 'transparent']
}),
borderTopColor: animate.interpolate({
inputRange: [0, 10],
outputRange: [color, color]
}),
borderRightColor: animate.interpolate({
inputRange: [0, 1, 2, 9, 10],
outputRange: ['transparent', 'transparent', color, color, 'transparent']
}),
borderBottomColor: animate.interpolate({
inputRange: [0, 2, 3, 9, 10],
outputRange: ['transparent', 'transparent', color, color, 'transparent']
})
}
};
useEffect(() => {
Animated.loop(
Animated.timing(animate, {
toValue: 10,
duration: duration * 4,
easing: Easing.inOut(Easing.ease)
})
).start();
}, [animate, duration]);
return (
<Animated.View style={[style, spinnerStyle.container, animateStyle.container]} {...props}>
<Animated.View style={[spinnerStyle.circle, animateStyle.circle]} />
<Animated.View style={[spinnerStyle.orbit, animateStyle.orbit]} />
</Animated.View>
);
};
FulfillingBouncingCircleSpinner.defaultProps = EpicDefaultProps;