@@ -4,25 +4,47 @@ import React, {
4
4
} from 'react' ;
5
5
6
6
import {
7
+ Animated ,
7
8
ART ,
9
+ StyleSheet ,
8
10
Text ,
9
11
View ,
10
12
} from 'react-native' ;
11
13
12
14
import Arc from './Shapes/Arc' ;
15
+ import withAnimation from './withAnimation' ;
13
16
14
- export default class ProgressCircle extends Component {
17
+ const CIRCLE = Math . PI * 2 ;
18
+
19
+ const AnimatedSurface = Animated . createAnimatedComponent ( ART . Surface ) ;
20
+ const AnimatedArc = Animated . createAnimatedComponent ( Arc ) ;
21
+
22
+ const styles = StyleSheet . create ( {
23
+ container : {
24
+ backgroundColor : 'transparent' ,
25
+ overflow : 'hidden' ,
26
+ } ,
27
+ } ) ;
28
+
29
+ export class ProgressCircle extends Component {
15
30
static propTypes = {
31
+ animated : PropTypes . bool ,
16
32
borderColor : PropTypes . string ,
17
33
borderWidth : PropTypes . number ,
18
34
color : PropTypes . string ,
35
+ children : React . PropTypes . node ,
19
36
direction : PropTypes . oneOf ( [ 'clockwise' , 'counter-clockwise' ] ) ,
20
37
formatText : PropTypes . func ,
21
38
indeterminate : PropTypes . bool ,
22
- progress : PropTypes . number ,
39
+ progress : PropTypes . oneOfType ( [
40
+ PropTypes . number ,
41
+ PropTypes . instanceOf ( Animated . Value ) ,
42
+ ] ) ,
43
+ rotation : PropTypes . instanceOf ( Animated . Value ) ,
23
44
showsText : PropTypes . bool ,
24
45
size : PropTypes . number ,
25
- textStyle : PropTypes . any ,
46
+ style : View . propTypes . style ,
47
+ textStyle : Text . propTypes . style ,
26
48
thickness : PropTypes . number ,
27
49
unfilledColor : PropTypes . string ,
28
50
} ;
@@ -31,15 +53,33 @@ export default class ProgressCircle extends Component {
31
53
borderWidth : 1 ,
32
54
color : 'rgba(0, 122, 255, 1)' ,
33
55
direction : 'clockwise' ,
34
- formatText : progress => Math . round ( progress * 100 ) + '%' ,
56
+ formatText : progress => ` ${ Math . round ( progress * 100 ) } %` ,
35
57
progress : 0 ,
36
58
showsText : false ,
37
59
size : 40 ,
38
60
thickness : 3 ,
39
61
} ;
40
62
63
+ constructor ( props , context ) {
64
+ super ( props , context ) ;
65
+
66
+ this . progressValue = 0 ;
67
+ }
68
+
69
+ componentWillMount ( ) {
70
+ if ( this . props . animated ) {
71
+ this . props . progress . addListener ( ( event ) => {
72
+ this . progressValue = event . value ;
73
+ if ( this . props . showsText || this . progressValue === 1 ) {
74
+ this . forceUpdate ( ) ;
75
+ }
76
+ } ) ;
77
+ }
78
+ }
79
+
41
80
render ( ) {
42
- let {
81
+ const {
82
+ animated,
43
83
borderColor,
44
84
borderWidth,
45
85
color,
@@ -48,73 +88,107 @@ export default class ProgressCircle extends Component {
48
88
formatText,
49
89
indeterminate,
50
90
progress,
91
+ rotation,
51
92
showsText,
52
93
size,
94
+ style,
53
95
textStyle,
54
96
thickness,
55
97
unfilledColor,
56
- ...restProps ,
98
+ ...restProps
57
99
} = this . props ;
58
100
59
- borderWidth = borderWidth || ( indeterminate ? 1 : 0 ) ;
101
+ const border = borderWidth || ( indeterminate ? 1 : 0 ) ;
60
102
61
- const radius = size / 2 - borderWidth ;
103
+ const radius = ( size / 2 ) - border ;
62
104
const offset = {
63
- top : borderWidth ,
64
- left : borderWidth ,
105
+ top : border ,
106
+ left : border ,
65
107
} ;
66
- const textOffset = borderWidth + thickness ;
67
- const textSize = size - textOffset * 2 ;
108
+ const textOffset = border + thickness ;
109
+ const textSize = size - ( textOffset * 2 ) ;
110
+
111
+ const Surface = rotation ? AnimatedSurface : ART . Surface ;
112
+ const Shape = animated ? AnimatedArc : Arc ;
113
+ const progressValue = animated ? this . progressValue : progress ;
114
+ const angle = animated ? Animated . multiply ( progress , CIRCLE ) : progress * CIRCLE ;
68
115
69
116
return (
70
- < View { ...restProps } >
71
- < ART . Surface
117
+ < View style = { [ styles . container , style ] } { ...restProps } >
118
+ < Surface
72
119
width = { size }
73
- height = { size } >
74
- { unfilledColor && progress !== 1 ? ( < Arc
75
- radius = { radius }
76
- offset = { offset }
77
- startAngle = { progress * 2 * Math . PI }
78
- endAngle = { 2 * Math . PI }
79
- direction = { direction }
80
- stroke = { unfilledColor }
81
- strokeWidth = { thickness } /> ) : false }
82
- { ! indeterminate && progress ? ( < Arc
83
- radius = { radius }
84
- offset = { offset }
85
- startAngle = { 0 }
86
- endAngle = { progress * 2 * Math . PI }
87
- direction = { direction }
88
- stroke = { color }
89
- strokeWidth = { thickness } /> ) : false }
90
- { borderWidth ?
91
- ( < Arc
120
+ height = { size }
121
+ style = { {
122
+ transform : [ {
123
+ rotate : indeterminate && rotation
124
+ ? rotation . interpolate ( {
125
+ inputRange : [ 0 , 1 ] ,
126
+ outputRange : [ '0deg' , '360deg' ] ,
127
+ } )
128
+ : '0deg' ,
129
+ } ] ,
130
+ } }
131
+ >
132
+ { unfilledColor && progressValue !== 1 ? (
133
+ < Shape
134
+ radius = { radius }
135
+ offset = { offset }
136
+ startAngle = { angle }
137
+ endAngle = { CIRCLE }
138
+ direction = { direction }
139
+ stroke = { unfilledColor }
140
+ strokeWidth = { thickness }
141
+ />
142
+ ) : false }
143
+ { ! indeterminate ? (
144
+ < Shape
145
+ radius = { radius }
146
+ offset = { offset }
147
+ startAngle = { 0 }
148
+ endAngle = { angle }
149
+ direction = { direction }
150
+ stroke = { color }
151
+ strokeWidth = { thickness }
152
+ />
153
+ ) : false }
154
+ { border ? (
155
+ < Arc
92
156
radius = { size / 2 }
93
157
startAngle = { 0 }
94
158
endAngle = { ( indeterminate ? 1.8 : 2 ) * Math . PI }
95
159
stroke = { borderColor || color }
96
- strokeWidth = { borderWidth } /> ) : false }
97
- </ ART . Surface >
98
- { ! indeterminate && progress && showsText ? (
99
- < View style = { {
100
- position : 'absolute' ,
101
- left : textOffset ,
102
- top : textOffset ,
103
- width : textSize ,
104
- height : textSize ,
105
- borderRadius : textSize / 2 ,
106
- alignItems : 'center' ,
107
- justifyContent : 'center' ,
108
- } } >
109
- < Text style = { [ {
110
- color : color ,
111
- fontSize : textSize / 4.5 ,
112
- fontWeight : '300' ,
113
- } , textStyle ] } > { formatText ( progress ) } </ Text >
160
+ strokeWidth = { border }
161
+ />
162
+ ) : false }
163
+ </ Surface >
164
+ { ! indeterminate && showsText ? (
165
+ < View
166
+ style = { {
167
+ position : 'absolute' ,
168
+ left : textOffset ,
169
+ top : textOffset ,
170
+ width : textSize ,
171
+ height : textSize ,
172
+ borderRadius : textSize / 2 ,
173
+ alignItems : 'center' ,
174
+ justifyContent : 'center' ,
175
+ } }
176
+ >
177
+ < Text
178
+ style = { [ {
179
+ color,
180
+ fontSize : textSize / 4.5 ,
181
+ fontWeight : '300' ,
182
+ } , textStyle ] }
183
+ >
184
+ { formatText ( progressValue ) }
185
+ </ Text >
114
186
</ View >
115
187
) : false }
116
188
{ children }
117
189
</ View >
118
190
) ;
119
191
}
120
192
}
193
+
194
+ export default withAnimation ( ProgressCircle ) ;
0 commit comments