思路 绘制两个圆环叠加,改变上部圆环的填充色~
技术点:需要
ART
,iOS
和Android
自行导入
Wedge.js
import React, { Component } from 'react';
import { ART } from 'react-native';
const { Shape, Path } = ART;
import PropTypes from 'prop-types'
/**
* Wedge is a React component for drawing circles, wedges and arcs. Like other
* ReactART components, it must be used in a .
*/
export default class Wedge extends Component {
constructor(props : any) {
super(props);
(this:any).circleRadians = Math.PI * 2;
(this:any).radiansPerDegree = Math.PI / 180;
(this:any)._degreesToRadians = this._degreesToRadians.bind(this);
}
/**
* _degreesToRadians(degrees)
*
* Helper function to convert degrees to radians
*
* @param {number} degrees
* @return {number}
*/
_degreesToRadians(degrees : number) : number {
if (degrees !== 0 && degrees % 360 === 0) { // 360, 720, etc.
return (this:any).circleRadians;
}
return degrees * (this:any).radiansPerDegree % (this:any).circleRadians;
}
/**
* _createCirclePath(or, ir)
*
* Creates the ReactART Path for a complete circle.
*
* @param {number} or The outer radius of the circle
* @param {number} ir The inner radius, greater than zero for a ring
* @return {object}
*/
_createCirclePath(originX : number, originY : number, or : number, ir : number) : Path {
const path = new Path();
path.move(originX, or + originY)
.arc(or * 2, 0, or)
.arc(-or * 2, 0, or);
if (ir) {
path.move(or - ir, 0)
.counterArc(ir * 2, 0, ir)
.counterArc(-ir * 2, 0, ir);
}
path.close();
return path;
}
/**
* _createArcPath(sa, ea, ca, or, ir)
*
* Creates the ReactART Path for an arc or wedge.
*
* @param {number} startAngle The starting degrees relative to 12 o'clock
* @param {number} endAngle The ending degrees relative to 12 o'clock
* @param {number} or The outer radius in pixels
* @param {number} ir The inner radius in pixels, greater than zero for an arc
* @return {object}
*/
_createArcPath(originX : number, originY : number, startAngle : number, endAngle : number, or : number, ir : number) : Path {
const path = new Path();
// angles in radians
const sa = this._degreesToRadians(startAngle);
const ea = this._degreesToRadians(endAngle);
// central arc angle in radians
const ca = sa > ea ? (this:any).circleRadians - sa + ea : ea - sa;
// cached sine and cosine values
const ss = Math.sin(sa);
const es = Math.sin(ea);
const sc = Math.cos(sa);
const ec = Math.cos(ea);
// cached differences
const ds = es - ss;
const dc = ec - sc;
const dr = ir - or;
// if the angle is over pi radians (180 degrees)
// we will need to let the drawing method know.
const large = ca > Math.PI;
// TODO (sema) Please improve theses comments to make the math
// more understandable.
//
// Formula for a point on a circle at a specific angle with a center
// at (0, 0):
// x = radius * Math.sin(radians)
// y = radius * Math.cos(radians)
//
// For our starting point, we offset the formula using the outer
// radius because our origin is at (top, left).
// In typical web layout fashion, we are drawing in quadrant IV
// (a.k.a. Southeast) where x is positive and y is negative.
//
// The arguments for path.arc and path.counterArc used below are:
// (endX, endY, radiusX, radiusY, largeAngle)
path.move(originX, originY) // move to starting point
.arc(or * ds, or * -dc, or, or, large) // outer arc
.line(dr * es, dr * -ec); // width of arc or wedge
if (ir) {
path.counterArc(ir * -ds, ir * dc, ir, ir, large); // inner arc
}
return path;
}
render() : any {
// angles are provided in degrees
const startAngle = this.props.startAngle;
const endAngle = this.props.endAngle;
// if (startAngle - endAngle === 0) {
// return null;
// }
// radii are provided in pixels
const innerRadius = this.props.innerRadius || 0;
const outerRadius = this.props.outerRadius;
const { originX, originY } = this.props;
// sorted radii
const ir = Math.min(innerRadius, outerRadius);
const or = Math.max(innerRadius, outerRadius);
let path;
// if (endAngle >= startAngle + 360) {
// path = this._createCirclePath(originX, originY, or, ir);
// } else {
path = this._createArcPath(originX, originY, startAngle, endAngle, or, ir);
// }
return ;
}
}
Wedge.propTypes = {
outerRadius: PropTypes.number.isRequired, // 圆弧半径
startAngle: PropTypes.number.isRequired, // 开始角度
endAngle: PropTypes.number.isRequired, // 结束角度
originX: PropTypes.number, // 左边的距离 不是圆心的X
originY: PropTypes.number, // 上部的距离 不是圆心的Y
innerRadius: PropTypes.number, //内部半径 用户画弧
}
Wedge.defaultProps = {
originX: 0,
originY: 0,
}
Progress.js
import React, {PureComponent} from 'react';
import {
View,
ART,
StyleSheet
} from "react-native"
var {
Surface, // 一个矩形可渲染的区域,是其他元素的容器
LinearGradient, // 颜色渐变
} = ART;
import Wedge from './Wedge'
import PropTypes from 'prop-types'
export default class Progress extends PureComponent {
/*public function*/
// 设置进度 取值范围 0 - 1
setProgress(progress){
if (progress >= 1.0) return
this.setState({
progress: progress
})
}
constructor(props) {
super(props);
this.state = {
progress: this.props.currentAngle,
}
}
render() {
// 渐变色,暂时没有搞懂 "宽" 的原理...
let Perimeter = Math.PI * this.props.radius
let linearGradient = new LinearGradient({
'.4': 'purple',
'.6': 'yellow',
},
"0", "0", String(Perimeter) - 80, String(this.props.annularHeight)
);
return (
{this.props.children}
);
}
}
const styles = StyleSheet.create({
contentView: {
position: 'absolute',
justifyContent: 'center',
alignItems: 'center'
}
});
Progress.publicFunction = {
setProgress: PropTypes.func, // 设置进度 取值范围 0 - 1
};
Progress.propTypes = {
radius: PropTypes.number, // 半径
annularHeight: PropTypes.number, // 内环高度
startAngle: PropTypes.number, // 开始角度 0 - 1
currentAngle: PropTypes.number, // 当前角度 0 - 1
bgColor: PropTypes.string, // 内环背景填充颜色
selectColor: PropTypes.string, // 内环背景选中填充颜色
};
Progress.defaultProps = {
radius: 50,
annularHeight: 2,
startAngle: 0, // 0 - 1
currentAngle: 0, // 0 - 1
bgColor: '#f5f5f5',
selectColor: 'blue'
};
使用一:只要圆环效果
使用二:圆环+内部视图
改变进度
this.progress.setProgress(0.3) // 0 - 1