react-native-komect-uikit
Version:
React Native UI Toolkit
180 lines (162 loc) • 4.29 kB
JavaScript
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
Animated,
ART,
Easing,
View,
} from 'react-native';
import Arc from './Shapes/Arc';
const AnimatedArc = Animated.createAnimatedComponent(Arc);
const MIN_ARC_ANGLE = 0.1;
const MAX_ARC_ANGLE = 1.5 * Math.PI;
export default class CircleSnail extends Component {
static propTypes = {
animating: PropTypes.bool,
color: PropTypes.oneOfType([
PropTypes.string,
PropTypes.arrayOf(PropTypes.string),
]),
children: PropTypes.node,
direction: PropTypes.oneOf(['clockwise', 'counter-clockwise']),
duration: PropTypes.number,
hidesWhenStopped: PropTypes.bool,
size: PropTypes.number,
spinDuration: PropTypes.number,
style: View.propTypes.style,
thickness: PropTypes.number,
};
static defaultProps = {
animating: true,
color: 'rgba(0, 122, 255, 1)',
direction: 'counter-clockwise',
hidesWhenStopped: false,
size: 40,
thickness: 3,
};
constructor(props) {
super(props);
this.state = {
startAngle: new Animated.Value(-MIN_ARC_ANGLE),
endAngle: new Animated.Value(0),
rotation: new Animated.Value(0),
colorIndex: 0,
};
}
componentDidMount() {
if (this.props.animating) {
this.animate();
this.spin();
}
}
componentWillReceiveProps(props) {
if (props.animating !== this.props.animating) {
if (props.animating) {
this.animate();
this.spin();
} else {
this.stopAnimations();
}
}
}
animate(iteration = 1) {
Animated.sequence([
Animated.timing(this.state.startAngle, {
toValue: (-MAX_ARC_ANGLE * iteration) - MIN_ARC_ANGLE,
duration: this.props.duration || 1000,
isInteraction: false,
easing: Easing.inOut(Easing.quad),
}),
Animated.timing(this.state.endAngle, {
toValue: -MAX_ARC_ANGLE * iteration,
duration: this.props.duration || 1000,
isInteraction: false,
easing: Easing.inOut(Easing.quad),
}),
]).start((endState) => {
if (endState.finished) {
if (Array.isArray(this.props.color)) {
this.setState({
colorIndex: iteration % this.props.color.length,
});
}
this.animate(iteration + 1);
}
});
}
spin() {
Animated.timing(this.state.rotation, {
toValue: 1,
duration: this.props.spinDuration || 5000,
easing: Easing.linear,
isInteraction: false,
}).start((endState) => {
if (endState.finished) {
this.state.rotation.setValue(0);
this.spin();
}
});
}
stopAnimations() {
this.state.startAngle.stopAnimation();
this.state.endAngle.stopAnimation();
this.state.rotation.stopAnimation();
}
render() {
const {
animating,
children,
color,
direction,
hidesWhenStopped,
size,
style,
thickness,
...restProps
} = this.props;
if (!animating && hidesWhenStopped) {
return null;
}
const radius = (size / 2) - thickness;
const offset = {
top: thickness,
left: thickness,
};
const directionFactor = direction === 'counter-clockwise' ? -1 : 1;
return (
<Animated.View
{...restProps}
style={[
style,
{
backgroundColor: 'transparent',
overflow: 'hidden',
transform: [{
rotate: this.state.rotation.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', `${directionFactor * 360}deg`],
}),
}],
},
]}
>
<ART.Surface
width={size}
height={size}
>
<AnimatedArc
direction={direction === 'counter-clockwise' ? 'clockwise' : 'counter-clockwise'}
radius={radius}
stroke={Array.isArray(color) ? color[this.state.colorIndex] : color}
offset={offset}
startAngle={this.state.startAngle}
endAngle={this.state.endAngle}
strokeCap="round"
strokeWidth={thickness}
/>
</ART.Surface>
{children}
</Animated.View>
);
}
}