如何实施React原生倒计时圈

时间:2018-03-14 09:24:51

标签: react-native countdown react-native-animatable

某人,请帮助我在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!')}                                 
   />

1 个答案:

答案 0 :(得分:0)

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

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>
    );
  }
}