mirror of
https://github.com/bartgryszko/react-native-circular-progress.git
synced 2026-01-18 16:13:10 +00:00
commit
f1ff66afa2
11
README.md
11
README.md
@ -60,7 +60,7 @@ You can also define a function, that'll receive current progress and for example
|
||||
</AnimatedCircularProgress>
|
||||
```
|
||||
|
||||
Finally, you can manually trigger a duration-based timing animation by putting a ref on the component and calling the `performLinearAnimation(toValue, duration)` function like so:
|
||||
Finally, you can manually trigger a duration-based timing animation by putting a ref on the component and calling the `performTimingAnimation(toValue, duration, easing)` function like so:
|
||||
```jsx
|
||||
<AnimatedCircularProgress
|
||||
ref='circularProgress'
|
||||
@ -68,7 +68,7 @@ Finally, you can manually trigger a duration-based timing animation by putting a
|
||||
/>
|
||||
```
|
||||
```javascript
|
||||
this.refs.circularProgress.performLinearAnimation(100, 8000); // Will fill the progress bar linearly in 8 seconds
|
||||
this.refs.circularProgress.performTimingAnimation(100, 8000, Easing.quad); // Will fill the progress bar linearly in 8 seconds
|
||||
```
|
||||
|
||||
## Configuration
|
||||
@ -80,12 +80,13 @@ You can configure the passing by following props:
|
||||
- **backgroundWidth** - thickness of the background line
|
||||
- **fill** - current, percentage fill (from 0 to 100)
|
||||
- **prefill** - percentage fill before the animation (from 0 to 100)
|
||||
- **tintColor** - color of a progress line
|
||||
- **backgroundColor** - color of a background for progress line. Use 'transparent' to hide
|
||||
- **tintColor** - color of the progress line
|
||||
- **backgroundColor** - color of the background for the progress line. If unspecified, no background will be rendered
|
||||
- **rotation** - by default, progress starts from the angle = 90⦝, you can change it by setting value from -360 to 360
|
||||
- **tension** - the tension value for the spring animation (see [here](https://facebook.github.io/react-native/docs/animations.html#core-api))
|
||||
- **friction** - the friction value for the spring animation (see [here](https://facebook.github.io/react-native/docs/animations.html#core-api))
|
||||
- **linecap** - the shape to be used at the ends of the circle. Possible values: butt (default), round or square. (see [here](https://developer.mozilla.org/en/docs/Web/SVG/Attribute/stroke-linecap))
|
||||
- **lineCap** - the shape to be used at the ends of the circle. Possible values: butt (default), round or square. (see [here](https://developer.mozilla.org/en/docs/Web/SVG/Attribute/stroke-linecap))
|
||||
- **arcSweepAngle** - the angle that you want your arc to sweep in the case where you don't want a full circle. Default is 360.
|
||||
- **children(fill)** - you can pass function as a child to receive current fill
|
||||
- **onAnimationComplete** - you can pass a callback function that will be invoked when animation is complete. (see [here](https://facebook.github.io/react-native/docs/animated.html#working-with-animations))
|
||||
- **onLinearAnimationComplete** - you can pass a callback function that will be invoked when linear animation is complete. (see [here](https://facebook.github.io/react-native/docs/animated.html#working-with-animations))
|
||||
|
||||
@ -55,15 +55,12 @@ export default class Example extends React.Component {
|
||||
fill={fill}
|
||||
tintColor="#00e0ff"
|
||||
backgroundColor="#3d5875"
|
||||
>
|
||||
{
|
||||
(fill) => (
|
||||
<Text style={styles.points}>
|
||||
{ Math.round(MAX_POINTS * fill / 100) }
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
</AnimatedCircularProgress>
|
||||
renderChild={(fill) => (
|
||||
<Text style={styles.points}>
|
||||
{ Math.round(MAX_POINTS * fill / 100) }
|
||||
</Text>
|
||||
)}
|
||||
/>
|
||||
|
||||
<AnimatedCircularProgress
|
||||
size={120}
|
||||
@ -71,7 +68,10 @@ export default class Example extends React.Component {
|
||||
backgroundWidth={5}
|
||||
fill={fill}
|
||||
tintColor="#00e0ff"
|
||||
backgroundColor="transparent"
|
||||
backgroundColor="#3d5875"
|
||||
arcSweepAngle={240}
|
||||
rotation={240}
|
||||
lineCap="round"
|
||||
/>
|
||||
|
||||
<AnimatedCircularProgress
|
||||
@ -82,6 +82,7 @@ export default class Example extends React.Component {
|
||||
onAnimationComplete={() => console.log('onAnimationComplete')}
|
||||
ref="circularProgress"
|
||||
backgroundColor="#3d5875"
|
||||
arcSweepAngle={180}
|
||||
/>
|
||||
|
||||
<Text style={[styles.pointsDelta, this.state.isMoving && styles.pointsDeltaActive]}>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"expo": {
|
||||
"sdkVersion": "23.0.0"
|
||||
"sdkVersion": "25.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"react-native-scripts": "1.7.0",
|
||||
"jest-expo": "^22.0.0",
|
||||
"jest-expo": "^25.0.0",
|
||||
"react-test-renderer": "16.0.0-beta.5"
|
||||
},
|
||||
"main": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
|
||||
@ -19,9 +19,9 @@
|
||||
"preset": "jest-expo"
|
||||
},
|
||||
"dependencies": {
|
||||
"expo": "^23.0.0",
|
||||
"react": "16.0.0",
|
||||
"react-native": "https://github.com/expo/react-native/archive/sdk-23.0.0.tar.gz",
|
||||
"expo": "^25.0.0",
|
||||
"react": "16.2.0",
|
||||
"react-native": "https://github.com/expo/react-native/archive/sdk-25.0.0.tar.gz",
|
||||
"react-native-circular-progress": "file:../"
|
||||
}
|
||||
}
|
||||
1163
example/yarn.lock
1163
example/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-circular-progress",
|
||||
"version": "0.1.2",
|
||||
"version": "0.2.0",
|
||||
"description": "React Native component for creating animated, circular progress with ReactART",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
|
||||
@ -15,32 +15,12 @@ export default class AnimatedCircularProgress extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
appState: AppState.currentState,
|
||||
chartFillAnimation: new Animated.Value(props.prefill || 0)
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.animateFill();
|
||||
AppState.addEventListener('change', this.handleAppStateChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
AppState.removeEventListener('change', this.handleAppStateChange);
|
||||
}
|
||||
|
||||
handleAppStateChange = nextAppState => {
|
||||
if (this.state.appState.match(/inactive|background/) &&
|
||||
nextAppState === 'active') {
|
||||
// Fix bug on Android where the drawing is not displayed after the app is
|
||||
// backgrounded / screen is turned off. Restart the animation when the app
|
||||
// comes back to the foreground.
|
||||
this.setState({
|
||||
chartFillAnimation: new Animated.Value(this.props.prefill || 0)
|
||||
});
|
||||
this.animateFill();
|
||||
}
|
||||
this.setState({ appState: nextAppState });
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
@ -62,13 +42,13 @@ export default class AnimatedCircularProgress extends React.Component {
|
||||
).start(onAnimationComplete);
|
||||
}
|
||||
|
||||
performLinearAnimation(toValue, duration) {
|
||||
performTimingAnimation(toValue, duration, easing = Easing.linear) {
|
||||
const { onLinearAnimationComplete } = this.props;
|
||||
|
||||
Animated.timing(this.state.chartFillAnimation, {
|
||||
toValue: toValue,
|
||||
easing: Easing.linear,
|
||||
duration: duration
|
||||
toValue,
|
||||
easing,
|
||||
duration,
|
||||
}).start(onLinearAnimationComplete);
|
||||
}
|
||||
|
||||
@ -79,8 +59,8 @@ export default class AnimatedCircularProgress extends React.Component {
|
||||
<AnimatedProgress
|
||||
{...other}
|
||||
fill={this.state.chartFillAnimation}
|
||||
/>
|
||||
)
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,7 +79,7 @@ AnimatedCircularProgress.propTypes = {
|
||||
friction: PropTypes.number,
|
||||
onAnimationComplete: PropTypes.func,
|
||||
onLinearAnimationComplete: PropTypes.func,
|
||||
}
|
||||
};
|
||||
|
||||
AnimatedCircularProgress.defaultProps = {
|
||||
tension: 7,
|
||||
|
||||
@ -1,22 +1,34 @@
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { View, ViewPropTypes, Platform, ART } from 'react-native';
|
||||
import { View, ViewPropTypes, Platform, ART, AppState } from 'react-native';
|
||||
const { Surface, Shape, Path, Group } = ART;
|
||||
import MetricsPath from 'art/metrics/path';
|
||||
|
||||
export default class CircularProgress extends React.Component {
|
||||
|
||||
state = {
|
||||
// We need to track this to mitigate a bug with RN ART on Android.
|
||||
// After being unlocked the <Surface> is not rendered.
|
||||
// To mitigate this we change the key-prop to forcefully update the <Surface>
|
||||
// It's horrible.
|
||||
// See https://github.com/facebook/react-native/issues/17565
|
||||
appState: AppState.currentState,
|
||||
}
|
||||
|
||||
circlePath(cx, cy, r, startDegree, endDegree) {
|
||||
let p = Path();
|
||||
p.path.push(0, cx + r, cy);
|
||||
p.path.push(4, cx, cy, r, startDegree * Math.PI / 180, endDegree * Math.PI / 180, 1);
|
||||
p.path.push(4, cx, cy, r, startDegree * Math.PI / 180, (endDegree * .9999) * Math.PI / 180, 1);
|
||||
return p;
|
||||
}
|
||||
|
||||
extractFill(fill) {
|
||||
return Math.min(100, Math.max(0, fill));
|
||||
}
|
||||
clampFill = fill => Math.min(100, Math.max(0, fill));
|
||||
|
||||
componentDidMount = () => AppState.addEventListener('change', this.handleAppStateChange);
|
||||
|
||||
componentWillUnmount = () => AppState.removeEventListener('change', this.handleAppStateChange);
|
||||
|
||||
handleAppStateChange = appState => this.setState({ appState });
|
||||
|
||||
render() {
|
||||
const {
|
||||
@ -27,13 +39,14 @@ export default class CircularProgress extends React.Component {
|
||||
backgroundColor,
|
||||
style,
|
||||
rotation,
|
||||
linecap,
|
||||
children
|
||||
lineCap,
|
||||
arcSweepAngle,
|
||||
renderChild,
|
||||
fill,
|
||||
} = this.props;
|
||||
|
||||
const fill = this.extractFill(this.props.fill);
|
||||
const backgroundPath = this.circlePath(size / 2, size / 2, size / 2 - width / 2, 0, 360 * .9999);
|
||||
const circlePath = this.circlePath(size / 2, size / 2, size / 2 - width / 2, 0, (360 * .9999) * fill / 100);
|
||||
const backgroundPath = this.circlePath(size / 2, size / 2, size / 2 - width / 2, 0, arcSweepAngle);
|
||||
const circlePath = this.circlePath(size / 2, size / 2, size / 2 - width / 2, 0, arcSweepAngle * this.clampFill(fill) / 100);
|
||||
const offset = size - (width * 2);
|
||||
|
||||
const childContainerStyle = {
|
||||
@ -45,37 +58,40 @@ export default class CircularProgress extends React.Component {
|
||||
borderRadius: offset / 2,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={style}>
|
||||
<Surface
|
||||
width={size}
|
||||
height={size}
|
||||
key={this.state.appState}
|
||||
style={{ backgroundColor: 'transparent' }}
|
||||
>
|
||||
<Group rotation={rotation - 90} originX={size/2} originY={size/2}>
|
||||
{ backgroundColor !== 'transparent' && (
|
||||
{ backgroundColor && (
|
||||
<Shape
|
||||
d={backgroundPath}
|
||||
stroke={backgroundColor}
|
||||
strokeWidth={backgroundWidth != null ? backgroundWidth : width}
|
||||
strokeWidth={backgroundWidth || width}
|
||||
strokeCap={lineCap}
|
||||
/>
|
||||
)}
|
||||
<Shape
|
||||
d={circlePath}
|
||||
stroke={tintColor}
|
||||
strokeWidth={width}
|
||||
strokeCap={linecap}
|
||||
strokeCap={lineCap}
|
||||
/>
|
||||
</Group>
|
||||
</Surface>
|
||||
{children && (
|
||||
{renderChild && (
|
||||
<View style={childContainerStyle}>
|
||||
{children(fill)}
|
||||
{renderChild(fill)}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,13 +104,14 @@ CircularProgress.propTypes = {
|
||||
tintColor: PropTypes.string,
|
||||
backgroundColor: PropTypes.string,
|
||||
rotation: PropTypes.number,
|
||||
linecap: PropTypes.string,
|
||||
children: PropTypes.func
|
||||
}
|
||||
lineCap: PropTypes.string,
|
||||
arcSweepAngle: PropTypes.number,
|
||||
renderChild: PropTypes.func
|
||||
};
|
||||
|
||||
CircularProgress.defaultProps = {
|
||||
tintColor: 'black',
|
||||
backgroundColor: '#e4e4e4',
|
||||
rotation: 90,
|
||||
linecap: 'butt'
|
||||
}
|
||||
lineCap: 'butt',
|
||||
arcSweepAngle: 360
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user