如何实现React原生倒计时圈

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何实现React原生倒计时圈相关的知识,希望对你有一定的参考价值。

有人,请帮助我在react-native中实现倒计时圈我希望计时器从300秒开始下降到0,其中有一个动画圈和文本(时间)。我尝试使用https://github.com/MrToph/react-native-countdown-circle

但问题是文本(时间)在一个完整的动画后更新。您还可以看到我在那里打开的问题。

以下是我的实现的代码片段

   <CountdownCircle
   seconds=300
   radius=25 
   borderWidth=3                                 
   color="#006400"                                 
   bgColor="#fff"                                 
   textStyle= fontSize: 15                                  
   onTimeElapsed=() =>                                 
   console.log('time over!')                                 
   />
答案

我更改了您在问题中提到的库文件。我知道这不好,但我试图解决你的问题。

import CountdownCircle from 'react-native-countdown-circle'//you can make your own file and import from that
 <CountdownCircle
          seconds=30
          radius=30
          borderWidth=8
          color="#ff003f"
          bgColor="#fff"
          textStyle= fontSize: 20 
          onTimeElapsed=() => console.log("Elapsed!")
        />

这是库文件,现在你可以将它作为一个组件使用,这里是react-native-countdown-circle库文件代码(修改后的代码)

import React from "react";
import 
  Easing,
  Animated,
  StyleSheet,
  Text,
  View,
  ViewPropTypes
 from "react-native";
import PropTypes from "prop-types";

// compatability for react-native versions < 0.44
const ViewPropTypesStyle = ViewPropTypes
  ? ViewPropTypes.style
  : View.propTypes.style;

const styles = StyleSheet.create(
  outerCircle: 
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#e3e3e3"
  ,
  innerCircle: 
    overflow: "hidden",
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#fff"
  ,
  leftWrap: 
    position: "absolute",
    top: 0,
    left: 0
  ,
  halfCircle: 
    position: "absolute",
    top: 0,
    left: 0,
    borderTopRightRadius: 0,
    borderBottomRightRadius: 0,
    backgroundColor: "#f00"
  
);

function calcInterpolationValuesForHalfCircle1(animatedValue,  shadowColor ) 
  const rotate = animatedValue.interpolate(
    inputRange: [0, 50, 50, 100],
    outputRange: ["0deg", "180deg", "180deg", "180deg"]
  );

  const backgroundColor = shadowColor;
  return  rotate, backgroundColor ;


function calcInterpolationValuesForHalfCircle2(
  animatedValue,
   color, shadowColor 
) 
  const rotate = animatedValue.interpolate(
    inputRange: [0, 50, 50, 100],
    outputRange: ["0deg", "0deg", "180deg", "360deg"]
  );

  const backgroundColor = animatedValue.interpolate(
    inputRange: [0, 50, 50, 100],
    outputRange: [color, color, shadowColor, shadowColor]
  );
  return  rotate, backgroundColor ;


function getInitialState(props) 
  console.log();
  return 
    circleProgress,
    secondsElapsed: 0,
    text: props.updateText(0, props.seconds),
    interpolationValuesHalfCircle1: calcInterpolationValuesForHalfCircle1(
      circleProgress,
      props
    ),
    interpolationValuesHalfCircle2: calcInterpolationValuesForHalfCircle2(
      circleProgress,
      props
    )
  ;

const circleProgress = new Animated.Value(0);

export default class PercentageCircle extends React.PureComponent 
  static propTypes = 
    seconds: PropTypes.number.isRequired,
    radius: PropTypes.number.isRequired,
    color: PropTypes.string,
    shadowColor: PropTypes.string, // eslint-disable-line react/no-unused-prop-types
    bgColor: PropTypes.string,
    borderWidth: PropTypes.number,
    containerStyle: ViewPropTypesStyle,
    textStyle: Text.propTypes.style,
    updateText: PropTypes.func,
    onTimeElapsed: PropTypes.func
  ;

  static defaultProps = 
    color: "#f00",
    shadowColor: "#999",
    bgColor: "#e9e9ef",
    borderWidth: 2,
    seconds: 10,
    children: null,
    containerStyle: null,
    textStyle: null,
    onTimeElapsed: () => null,
    updateText: (elapsedSeconds, totalSeconds) =>
      (totalSeconds - elapsedSeconds).toString()
  ;

  constructor(props) 
    super(props);

    this.state = getInitialState(props);
    this.restartAnimation();
  

  componentWillReceiveProps(nextProps) 
    if (this.props.seconds !== nextProps.seconds) 
      this.setState(getInitialState(nextProps));
    
  

  onCircleAnimated = ( finished ) => 
    // if animation was interrupted by stopAnimation don't restart it.
    if (!finished) return;

    const secondsElapsed = this.state.secondsElapsed + 1;
    const callback =
      secondsElapsed < this.props.seconds
        ? this.restartAnimation
        : this.props.onTimeElapsed;
    const updatedText = this.props.updateText(
      secondsElapsed,
      this.props.seconds
    );
    this.setState(
      
        ...getInitialState(this.props),
        secondsElapsed,
        text: updatedText
      ,
      callback
    );
  ;

  restartAnimation = () => 
    Animated.timing(this.state.circleProgress, 
      toValue:
        parseFloat(JSON.stringify(this.state.circleProgress)) +
        100 / this.props.seconds,
      duration: 1000,
      easing: Easing.linear
    ).start(this.onCircleAnimated);
  ;

  renderHalfCircle( rotate, backgroundColor ) 
    const  radius  = this.props;

    return (
      <View
        style=[
          styles.leftWrap,
          
            width: radius,
            height: radius * 2
          
        ]
      >
        <Animated.View
          style=[
            styles.halfCircle,
            
              width: radius,
              height: radius * 2,
              borderRadius: radius,
              backgroundColor,
              transform: [
                 translateX: radius / 2 ,
                 rotate ,
                 translateX: -radius / 2 
              ]
            
          ]
        />
      </View>
    );
  

  renderInnerCircle() 
    const radiusMinusBorder = this.props.radius - this.props.borderWidth;
    return (
      <View
        style=[
          styles.innerCircle,
          
            width: radiusMinusBorder * 2,
            height: radiusMinusBorder * 2,
            borderRadius: radiusMinusBorder,
            backgroundColor: this.props.bgColor,
            ...this.props.containerStyle
          
        ]
      >
        <Text style=this.props.textStyle>this.state.text</Text>
      </View>
    );
  

  render() 
    const 
      interpolationValuesHalfCircle1,
      interpolationValuesHalfCircle2
     = this.state;
    return (
      <View
        style=[
          styles.outerCircle,
          
            width: this.props.radius * 2,
            height: this.props.radius * 2,
            borderRadius: this.props.radius,
            backgroundColor: this.props.color
          
        ]
      >
        this.renderHalfCircle(interpolationValuesHalfCircle1)
        this.renderHalfCircle(interpolationValuesHalfCircle2)
        this.renderInnerCircle()
      </View>
    );
  

以上是关于如何实现React原生倒计时圈的主要内容,如果未能解决你的问题,请参考以下文章

React中发送验证码 倒计时效果组件编写

如何每次在同一个视图上与 react native expo 倒计时

原生JS轻松实现倒计时功能

原生js实现倒计时

原生js实现一个简单的倒计时功能

React-Native开发之原生模块封装(Android)升级版