美文网首页ReactNative
React-Native ART绘制圆形进度条

React-Native ART绘制圆形进度条

作者: 精神病患者link常 | 来源:发表于2018-11-19 17:41 被阅读115次
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 <Surface>.
 */
export default class Wedge extends Component<void, any, any> {

    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 <Shape {...this.props} d={path} />;
    }
}
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 (
            <View>

                <Surface width={this.props.radius * 2} height={this.props.radius * 2}>
                    <Wedge
                        outerRadius={this.props.radius}
                        innerRadius={this.props.radius - this.props.annularHeight}
                        startAngle={this.props.startAngle}
                        endAngle={360}
                        originX={this.props.radius}
                        originY={0}
                        fill={this.props.bgColor} />
                    <Wedge
                        outerRadius={this.props.radius}
                        innerRadius={this.props.radius - this.props.annularHeight}
                        startAngle={this.props.startAngle}
                        endAngle={this.state.progress * 360.0}
                        originX={this.props.radius}
                        originY={0}
                        fill={this.props.selectColor} />
                </Surface>
                <View style={[styles.contentView,{
                    width: (this.props.radius - this.props.annularHeight) * 2,
                    height: (this.props.radius - this.props.annularHeight) * 2,
                    left: this.props.annularHeight,
                    top: this.props.annularHeight}]}
                >
                    {this.props.children}
                </View>
            </View>
        );
    }
}
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'
};


使用一:只要圆环效果

 <Progress ref={(ref)=>this.progress = ref} />

使用二:圆环+内部视图

 <Progress ref={(ref)=>this.progress = ref} >
    <Text>你好</Text>
    ......
</Progress>

改变进度

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

相关文章

  • React-Native ART绘制圆形进度条

    思路 绘制两个圆环叠加,改变上部圆环的填充色~ 技术点:需要ART,iOS和Android自行导入 Wedge.j...

  • react-native实现画笔功能

    ART相关 react-native之ART 配置IOS 参考 react-native之ART绘图详解 手势相关...

  • React Native 盾牌形进度条

    前序 因项目需求需要使用React-native封装一个特殊形状的进度条。网上大神封装好的进度条都是圆形或者长条的...

  • Android自定义圆形进度条

    绘制自定义的圆形进度条,分为三个步骤,内圆、外圆、文字。其中内圆和文字比较好绘制,进度条的变化是由外圆来控制的,所...

  • 圆形进度条的绘制

    做iOS开发也有很长一段时间了,在这段时间里也一直没有什么写过什么东西,更多的是在看别人的博客,学习东西,今天闲来...

  • LibGdx绘制圆形进度条

    案例一: 实现方式二:

  • UIBezierPath与CAShapeLayer混合使用

    一、使用CAShapeLayer绘制一个圆 二、给圆加圆形进度条动画 这时我们会发现进度条的起始点不是在顶端,把c...

  • react-native 圆形进度条

    项目中录制视频需要用到圆形进度条,从网上搜了很多,终于发现一个好用的组件react-native-progress...

  • iOS 各种圆形进度条

    iOS 各种圆形进度条:UAProgressView iOS手把手教你实现圆形进度条

  • Android自定义圆形进度条学习

    Android中圆形进度条的应用还是挺多的,最近学习实现了圆形进度条。 思路 要实现圆形进度条, 首先要画灰色背景...

网友评论

    本文标题:React-Native ART绘制圆形进度条

    本文链接:https://www.haomeiwen.com/subject/xvpafqtx.html