Skip to content

Commit 4229b31

Browse files
committed
Port all the spinners from SpinKit
1 parent e8efa2b commit 4229b31

File tree

17 files changed

+1092
-7
lines changed

17 files changed

+1092
-7
lines changed

example/App.tsx

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,87 @@
11
import React from 'react'
2-
import { StyleSheet, View } from 'react-native'
3-
import { Plane } from 'react-native-animated-spinkit'
2+
import { View, StatusBar, Text, StyleSheet } from 'react-native'
3+
import {
4+
Plane,
5+
Chase,
6+
Bounce,
7+
Wave,
8+
Wander,
9+
Pulse,
10+
Flow,
11+
Circle,
12+
Grid,
13+
CircleFade,
14+
Fold,
15+
Swing,
16+
} from 'react-native-animated-spinkit'
17+
18+
const spinners = [
19+
{ component: Plane, backgroundColor: '#d35400' },
20+
{ component: Chase, backgroundColor: '#2c3e50' },
21+
{ component: Bounce, backgroundColor: '#1abc9c' },
22+
{ component: Wave, backgroundColor: '#2980b9' },
23+
{ component: Wander, backgroundColor: '#7f8c8d' },
24+
{ component: Pulse, backgroundColor: '#ffcb65' },
25+
{ component: Swing, backgroundColor: '#d35400' },
26+
{ component: Flow, backgroundColor: '#27ae60' },
27+
{ component: Circle, backgroundColor: '#d35400' },
28+
{ component: Grid, backgroundColor: '#2c3e50' },
29+
{ component: CircleFade, backgroundColor: '#1abc9c' },
30+
{ component: Fold, backgroundColor: '#2980b9' },
31+
]
432

533
export default function App() {
634
return (
735
<View style={styles.container}>
8-
<Plane />
36+
<StatusBar barStyle="light-content" />
37+
{Array(Math.round(spinners.length / 3))
38+
.fill(null)
39+
.map((_, rowIndex) => (
40+
<View key={rowIndex} style={styles.row}>
41+
{spinners
42+
.slice(rowIndex * 3, rowIndex * 3 + 3)
43+
.map((spinner, index) => {
44+
const Spinner = spinner.component
45+
return (
46+
<View
47+
style={[
48+
styles.cell,
49+
{
50+
backgroundColor: spinner.backgroundColor,
51+
},
52+
]}
53+
key={index}
54+
>
55+
<Spinner color="#FFF" />
56+
<Text style={styles.componentLabel}>
57+
{`<${spinner.component.name} \/>`}
58+
</Text>
59+
</View>
60+
)
61+
})}
62+
</View>
63+
))}
964
</View>
1065
)
1166
}
1267

1368
const styles = StyleSheet.create({
1469
container: {
1570
flex: 1,
16-
backgroundColor: '#fff',
71+
},
72+
componentLabel: {
73+
position: 'absolute',
74+
bottom: 14,
75+
color: '#FFF',
76+
fontWeight: 'bold',
77+
opacity: 0.7,
78+
},
79+
row: {
80+
flexDirection: 'row',
81+
flex: 1,
82+
},
83+
cell: {
84+
flex: 1,
1785
alignItems: 'center',
1886
justifyContent: 'center',
1987
},

src/AnimationContainer.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import * as React from 'react'
2+
import { Animated } from 'react-native'
3+
4+
export interface Props {
5+
animation: () => Animated.CompositeAnimation
6+
}
7+
export default class AnimationContainer extends React.Component<Props> {
8+
animation: Animated.CompositeAnimation
9+
10+
constructor(props: Props) {
11+
super(props)
12+
13+
const { animation } = this.props
14+
this.animation = animation()
15+
}
16+
17+
componentDidMount() {
18+
this.animation.start()
19+
}
20+
21+
componentWillUnmount() {
22+
this.animation.stop()
23+
}
24+
25+
render() {
26+
return this.props.children
27+
}
28+
}

src/Bounce.tsx

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import * as React from 'react'
2+
import { Animated, View } from 'react-native'
3+
import { SpinnerProps, defaultProps } from './SpinnerProps'
4+
import AnimationContainer from './AnimationContainer'
5+
import { anim, createAnimatedValues } from './utils'
6+
7+
export default class Bounce extends React.Component<SpinnerProps> {
8+
static defaultProps = defaultProps
9+
values = createAnimatedValues(2)
10+
11+
render() {
12+
const { size, color, style, ...rest } = this.props
13+
const circleStyle = {
14+
position: 'absolute',
15+
width: size,
16+
height: size,
17+
backgroundColor: color,
18+
borderRadius: size / 2,
19+
opacity: 0.6,
20+
}
21+
return (
22+
<AnimationContainer
23+
animation={() =>
24+
Animated.stagger(
25+
1000,
26+
this.values.map(value =>
27+
anim({
28+
duration: 2000,
29+
value: value,
30+
keyframes: [0, 45, 55, 100],
31+
})
32+
)
33+
)
34+
}
35+
>
36+
<View style={[{ width: size, height: size }, style]} {...rest}>
37+
{this.values.map((value, index) => (
38+
<Animated.View
39+
key={index}
40+
style={[
41+
circleStyle,
42+
{
43+
transform: [
44+
{
45+
scale: value.interpolate({
46+
inputRange: [0, 45, 55, 100],
47+
outputRange: [0.01, 1, 1, 0.01],
48+
}),
49+
},
50+
],
51+
},
52+
]}
53+
/>
54+
))}
55+
</View>
56+
</AnimationContainer>
57+
)
58+
}
59+
}

src/Chase.tsx

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import * as React from 'react'
2+
import { Animated, Easing } from 'react-native'
3+
import { SpinnerProps, defaultProps } from './SpinnerProps'
4+
import AnimationContainer from './AnimationContainer'
5+
import { anim, createAnimatedValues } from './utils'
6+
7+
export default class Chase extends React.Component<SpinnerProps> {
8+
static defaultProps = defaultProps
9+
chaseDotValues = createAnimatedValues(6)
10+
chaseDotBeforeValues = createAnimatedValues(6)
11+
chase = new Animated.Value(0)
12+
13+
render() {
14+
const { size, color, style, ...rest } = this.props
15+
const circleStyle = {
16+
position: 'absolute',
17+
width: size / 4,
18+
height: size / 4,
19+
backgroundColor: color,
20+
borderRadius: size / 8,
21+
}
22+
return (
23+
<AnimationContainer
24+
animation={() =>
25+
Animated.parallel([
26+
Animated.stagger(
27+
100,
28+
this.chaseDotValues.map(value =>
29+
anim({
30+
duration: 2000,
31+
value: value,
32+
keyframes: [0, 80, 100],
33+
})
34+
)
35+
),
36+
Animated.stagger(
37+
100,
38+
this.chaseDotBeforeValues.map(value =>
39+
anim({
40+
duration: 2000,
41+
value: value,
42+
keyframes: [0, 50, 100],
43+
})
44+
)
45+
),
46+
anim({
47+
duration: 2500,
48+
easing: Easing.linear,
49+
value: this.chase,
50+
}),
51+
])
52+
}
53+
>
54+
<Animated.View
55+
style={[
56+
{
57+
width: size,
58+
height: size,
59+
alignItems: 'center',
60+
justifyContent: 'center',
61+
transform: [
62+
{
63+
rotate: this.chase.interpolate({
64+
inputRange: [0, 100],
65+
outputRange: ['0deg', '360deg'],
66+
}),
67+
},
68+
],
69+
},
70+
style,
71+
]}
72+
{...rest}
73+
>
74+
{this.chaseDotValues.map((value, index) => (
75+
<Animated.View
76+
key={index}
77+
style={[
78+
circleStyle,
79+
{
80+
transform: [
81+
{
82+
rotate: value.interpolate({
83+
inputRange: [0, 80, 100],
84+
outputRange: ['0deg', '360deg', '360deg'],
85+
}),
86+
},
87+
{ translateY: -size / 2 + size / 8 },
88+
{
89+
scale: this.chaseDotBeforeValues[index].interpolate({
90+
inputRange: [0, 50, 100],
91+
outputRange: [1, 0.4, 1],
92+
}),
93+
},
94+
],
95+
},
96+
]}
97+
/>
98+
))}
99+
</Animated.View>
100+
</AnimationContainer>
101+
)
102+
}
103+
}

src/Circle.tsx

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import * as React from 'react'
2+
import { Animated, View } from 'react-native'
3+
import { SpinnerProps, defaultProps } from './SpinnerProps'
4+
import AnimationContainer from './AnimationContainer'
5+
import { anim, createAnimatedValues } from './utils'
6+
7+
export default class Circle extends React.Component<SpinnerProps> {
8+
static defaultProps = defaultProps
9+
values = createAnimatedValues(12)
10+
11+
render() {
12+
const { size, color, style, ...rest } = this.props
13+
const circleStyle = {
14+
position: 'absolute',
15+
width: size * 0.15,
16+
height: size * 0.15,
17+
backgroundColor: color,
18+
borderRadius: (size * 0.15) / 2,
19+
}
20+
return (
21+
<AnimationContainer
22+
animation={() =>
23+
Animated.stagger(
24+
100,
25+
this.values.map(value =>
26+
anim({
27+
duration: 1200,
28+
value: value,
29+
keyframes: [0, 40, 80, 100],
30+
})
31+
)
32+
)
33+
}
34+
>
35+
<View
36+
style={[
37+
{
38+
width: size,
39+
height: size,
40+
alignItems: 'center',
41+
justifyContent: 'center',
42+
},
43+
style,
44+
]}
45+
{...rest}
46+
>
47+
{this.values.map((value, index) => (
48+
<Animated.View
49+
key={index}
50+
style={[
51+
circleStyle,
52+
{
53+
transform: [
54+
{
55+
rotate: `${index * 30}deg`,
56+
},
57+
{ translateY: -size / 2 + (size * 0.15) / 2 },
58+
{
59+
scale: value.interpolate({
60+
inputRange: [0, 40, 80, 100],
61+
outputRange: [0.01, 1, 0.01, 0.01],
62+
}),
63+
},
64+
],
65+
},
66+
]}
67+
/>
68+
))}
69+
</View>
70+
</AnimationContainer>
71+
)
72+
}
73+
}

0 commit comments

Comments
 (0)