Merge pull request #1 from bgryszko/master

merge
This commit is contained in:
Grzegorz Mandziak 2018-05-24 08:59:31 +02:00 committed by GitHub
commit f1ff66afa2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 809 additions and 497 deletions

View File

@ -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))

View File

@ -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]}>

View File

@ -1,5 +1,5 @@
{
"expo": {
"sdkVersion": "23.0.0"
"sdkVersion": "25.0.0"
}
}

View File

@ -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:../"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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": {

View File

@ -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,

View File

@ -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
};