React-Native ART绘制圆形进度条

React-Native ART绘制圆形进度条_第1张图片
image.png

思路 绘制两个圆环叠加,改变上部圆环的填充色~

技术点:需要ARTiOSAndroid自行导入

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 = ref} />

使用二:圆环+内部视图

 this.progress = ref} >
    你好
    ......

改变进度

this.progress.setProgress(0.3)  // 0 - 1

你可能感兴趣的:(React-Native ART绘制圆形进度条)