对react-native-percentage-circle修改,实现圆环旋转一定角度

最近在项目中要用到[react-native-percentage-circle][1]组件实现进度条和画圆环。UI界面要实现如下效果

clipboard.png

可以看出要实现两个圆环嵌套,实现同心圆还是比较简单的,react-native-percentage-circle组件支持子元素,所以,在外面圆环里面嵌套一个同心圆环,然后设置样式就行了。具体代码如下:   
<PercentageCircle radius={70} percent={100} color={'#ffffff'} bgcolor={"#ffffff"} innerColor={"#ffffff"} borderWidth={8}>
    <View style={{flex:1,justifyContent:'center',alignItems: 'center',}}>
        <PercentageCircle radius={60} percent={49} rotate={10} bgcolor={'#ff912f'} color={"#ffac48"} innerColor={"#ffffff"} borderWidth={15}>
        <Text style={{fontFamily: "MicrosoftYaHei",fontSize: 22,lineHeight: 27,color: "#545453"}}> 1990笔</Text>                 
        </PercentageCircle>
    </View>
</PercentageCircle>
然而要实现里面圆环旋转就有点难度了,首先目前该组件最新版本v1.0.6并不支持直接旋转

clipboard.png

因此,首先我们想到可能要用的transform来实现,但实践发现有各种问题。最后,本人决定是否可以通过修改源码实现旋转效果,对组件的index.js研究发现可以对组件加上一个props属性rotate,实现圆环旋转效果。

第一步:在PercentageCircle类propTypes中添加一个rotate属性。

clipboard.png

第二步:在constructor中定义一个新的变量rotate。

clipboard.png

第三步:对if进行修改,要同时修改constructor函数和componentWillReceiveProps()函数

clipboard.png

NOTE:这里rotate本人未设定值范围,但建议0-50,如果大于50,失去了意义,可以通过背景颜色改变,大家在代码中可以自己设定rotate的取值范围。

最后附上本人在git上的Issues的评论,以及index.js代码

/** React Native Percentage Circle
 ** @github  https://github.com/JackPu/react-native-percentage-circle
 ** React Native Version >=0.25
 ** to fixed react native version
 **/

import React, {
  Component
} from 'react';
import {
  StyleSheet,
  View,
  Text,
} from 'react-native';

const styles = StyleSheet.create({
  circle: {
    overflow: 'hidden',
    position: 'relative',
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#e3e3e3',
  },
  leftWrap: {
    overflow: 'hidden',
    position: 'absolute',
    top: 0,
  },
  rightWrap: {
    position: 'absolute',

  },

  loader: {
    position: 'absolute',
    left: 0,
    top: 0,
    borderRadius: 1000,

  },

  innerCircle: {
    overflow: 'hidden',
    position: 'relative',
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 11,
    color: '#888',
  },
});

class PercentageCircle extends Component {
  propTypes: {
    color: React.PropTypes.string,
    bgcolor: React.PropTypes.string,
    innerColor: React.PropTypes.string,
    radius: React.PropTypes.number,
    percent: React.PropTypes.number,
    borderWidth: React.Proptypes.number,
    textStyle: React.Proptypes.array,
    disabled: React.PropTypes.bool,
    rotate: React.Proptypes.number, //定义旋转角度
  }


  constructor(props) {
    super(props);

    let percent = this.props.percent;
    let leftTransformerDegree = '0deg';
    let rightTransformerDegree = '0deg';
    //初始化值
    let rotate = this.props.rotate;
    if (typeof rotate == 'undefined') {
      rotate = 0;
    }
    if (percent >= 50) {
      //rightTransformerDegree = '180deg';
      //leftTransformerDegree = (percent - 50) * 3.6 + 'deg';
      rightTransformerDegree = 180 + rotate * 3.6 + 'deg';
      leftTransformerDegree = (percent + rotate - 50) * 3.6 + 'deg';
    } else {
      //rightTransformerDegree = percent * 3.6 + 'deg';
      rightTransformerDegree = (percent + rotate - 50) * 3.6 + 'deg';
      leftTransformerDegree = rotate * 3.6 + 'deg';
    }

    this.state = {
      percent: this.props.percent,
      borderWidth: this.props.borderWidth < 2 || !this.props.borderWidth ? 2 : this.props.borderWidth,
      leftTransformerDegree: leftTransformerDegree,
      rightTransformerDegree: rightTransformerDegree,
      textStyle: this.props.textStyle ? this.props.textStyle : null
    };
  }

  componentWillReceiveProps(nextProps) {
    let percent = nextProps.percent;
    let leftTransformerDegree = '0deg';
    let rightTransformerDegree = '0deg';

    /*
    if (percent >= 50) {
      rightTransformerDegree = '180deg';
      leftTransformerDegree = (percent - 50) * 3.6 + 'deg';
    } else {
      rightTransformerDegree = '0deg';
      leftTransformerDegree = -(50 - percent) * 3.6 + 'deg';
    }
    */
    //初始化值
    let rotate = this.props.rotate;
    if (typeof rotate == 'undefined') {
      rotate = 0;
    }
    if (percent >= 50) {
      //rightTransformerDegree = '180deg';
      //leftTransformerDegree = (percent - 50) * 3.6 + 'deg';
      rightTransformerDegree = 180 + rotate * 3.6 + 'deg';
      leftTransformerDegree = (percent + rotate - 50) * 3.6 + 'deg';
    } else {
      //rightTransformerDegree = percent * 3.6 + 'deg';
      rightTransformerDegree = (percent + rotate - 50) * 3.6 + 'deg';
      leftTransformerDegree = rotate * 3.6 + 'deg';
    }

    this.setState({
      percent: this.props.percent,
      borderWidth: this.props.borderWidth < 2 || !this.props.borderWidth ? 2 : this.props.borderWidth,
      leftTransformerDegree: leftTransformerDegree,
      rightTransformerDegree: rightTransformerDegree
    });
  }

  render() {
    if (this.props.disabled) {
      return (
        <View style={[styles.circle,{
          width:this.props.radius*2,
          height: this.props.radius*2,
          borderRadius:this.props.radius
        }]}>
          <Text style={styles.text}>{this.props.disabledText}</Text>
        </View>
      );
    }
    return (
      <View style={[styles.circle,{
        width:this.props.radius*2,
        height: this.props.radius*2,
        borderRadius:this.props.radius,
        backgroundColor: this.props.bgcolor
      }]}>
        <View style={[styles.leftWrap,{
          width: this.props.radius,
          height: this.props.radius * 2,
          left:0,
        }]}>
          <View style={[styles.loader,{
            left: this.props.radius,
            width:this.props.radius,
            height: this.props.radius*2,
            borderTopLeftRadius:0,
            borderBottomLeftRadius:0,
            backgroundColor:this.props.color,
            transform:[{translateX:-this.props.radius/2},{rotate:this.state.leftTransformerDegree},{translateX:this.props.radius/2}],  
          }]}></View>
        </View>
        <View style={[styles.leftWrap,{
          left:this.props.radius,
          width: this.props.radius,
          height: this.props.radius * 2,
        }]}>
          <View style={[styles.loader,{
            left:-this.props.radius,
            width:this.props.radius,
            height: this.props.radius*2,
            borderTopRightRadius:0,
            borderBottomRightRadius:0,
            backgroundColor: this.props.percent < 50 ? this.props.bgcolor : this.props.color,
            transform:[{translateX:this.props.radius/2},{rotate:this.state.rightTransformerDegree},{translateX:-this.props.radius/2}],  
          }]}></View>
        </View>
        <View style={[styles.innerCircle,{
              width:(this.props.radius - this.state.borderWidth)*2, 
              height:(this.props.radius - this.state.borderWidth)*2,
              borderRadius:this.props.radius - this.state.borderWidth,
              backgroundColor: this.props.innerColor,
            }]}>
          {this.props.children ? this.props.children :
            <Text style={[styles.text, this.state.textStyle]}>{this.props.percent}%</Text>}
        </View>

      </View>
    );
  }
}

// set some attributes default value
PercentageCircle.defaultProps = {
  bgcolor: '#e3e3e3',
  innerColor: '#fff'
};

module.exports = PercentageCircle;

s://github.com/JackPu/react-native-percentage-circle

posted @ 2020-06-10 17:29  10年码农  阅读(685)  评论(0编辑  收藏  举报