设置我喜欢的博览会计时器的开始时间

问题描述 投票:0回答:1

我在世博会上有一个工作循环计时器。它由 2 个计时器组成,当一个计时器完成时,下一个计时器开始,然后它们进入循环。每个人都有自己独立的时间。

我想添加一个初始时间,以便它们按照我偏好的“时钟时间”开始运行。

import * as React from 'react';
import { Text, View, StyleSheet, Animated, Button } from 'react-native';
import Constants from 'expo-constants';
import { CountdownCircleTimer } from 'react-native-countdown-circle-timer';

const duration = [10, 20];

export default function App() {
  const [isPlaying, setIsPlaying] = React.useState(true);
  const [timeIndex, setTimeIndex] = React.useState(0);

  return (
    <View style={styles.container}>
      <CountdownCircleTimer
        key={timeIndex}
        isPlaying={isPlaying}
        duration={duration[timeIndex]} 
        colors={[
          ['#FFFF00', 0.4], 
          ['#0000ff', 0.4],
        ]}
        onComplete={() => {
          setTimeIndex((index) => {
            let newIndex = index + 1;
            if (newIndex >= duration.length) {
              newIndex = 0;
            }
            return newIndex;
          });
          return [true];
        }}>
        {({ remainingTime, animatedColor }) => (
          <Animated.Text style={{ color: animatedColor, fontSize: 40 }}>
            {remainingTime}
          </Animated.Text>
        )}
      </CountdownCircleTimer>
      <Button
        title="Toggle Playing"
        onPress={() => setIsPlaying((prev) => !prev)}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
    padding: 8,
  },
});
javascript reactjs react-native expo countdowntimer
1个回答
0
投票

我创建了一个钩子

useClock
,它可以配置其间隔运行的频率、间隔何时开始,并提供间隔和开始时间之间可以经过的时间上限:

import { useState, useRef, useEffect } from 'react';
import { convertDate } from '../helpers/time';

export default function useClock({
  intervalInSeconds = 1,
  atMoment,
  startTime,
  maxTimeElaspedInSeconds = 15,
}) {
  const hasStarted = useRef(false);
  // hook doesnt need to return a time but I was using this state for debugging
  const [time, setTime] = useState(new Date());
  useEffect(() => {
    const interval = setInterval(() => {
      const newTime = new Date();
      const timeDiff = newTime.getTime() - startTime.getTime();
      // if waiting for next interval would call atMoment too late
      // call atMoment in current interval
      const shouldRun =
        timeDiff + intervalInSeconds * 1000 > maxTimeElaspedInSeconds * 1000;
      if (shouldRun && !hasStarted.current) {
        console.log('Running at', convertDate(newTime));
        hasStarted.current = true;
        atMoment();
      }
      setTime(newTime);
    }, intervalInSeconds * 1000);
    return () => {
      clearInterval(interval);
      hasStarted.current = false;
    };
  }, [atMoment, startTime, intervalInSeconds, maxTimeElaspedInSeconds]);
  return time;
}

使用此功能,您可以在指定时间运行函数:

import { Text, SafeAreaView, StyleSheet, Button, Animated } from 'react-native';
import useClock from './hooks/useClock';
import { useRef, useState, useEffect } from 'react';
import { createFutureDateInMinutes,convertDate } from './helpers/time';
import { CountdownCircleTimer } from 'react-native-countdown-circle-timer';

const duration = [10,20]
const intervalInSeconds = 15

export default function App() {
  // todo: you will have to convert time string into a date object
  // for testing purposes I just set the start time to a 30 seconds
  // after the first render
  const startTime = useRef(createFutureDateInMinutes(30/60)).current;
  const [isPlaying, setIsPlaying] = useState(false);
  const [timeIndex, setTimeIndex] = useState(0);

  // useTime tries to estimate what the next 
  const time = useClock({
    startTime,
    // maximum time allowed to elaspe before calling atMoment
    maxTimeElaspedInSeconds:1,
    // Im not sure of performance effect of running an interval
    // every second has, but depending on the complexity of your
    // app you  might need to make this variable as big as possible
    // this hook guesses how much time will pass before its called again
    // and if it exceeds maxTimeElaspedInSeconds, will call the hook earlier
    intervalInSeconds,
    atMoment: () => {
      console.log('start time reached')
      setIsPlaying(true);
    },
  });
 
  return (
    <SafeAreaView style={styles.container}>
      <Text>Start time:{convertDate(startTime)}</Text>
      <Text>Current time:{convertDate(time)}</Text>
      <CountdownCircleTimer
        key={timeIndex}
        isPlaying={isPlaying}
        duration={duration[timeIndex]} 
        colors={[
          ['#FFFF00', 0.4], 
          ['#0000ff', 0.4],
        ]}
        onComplete={() => {
          setTimeIndex((index) => {
            let newIndex = index + 1;
            if (newIndex >= duration.length) {
              newIndex = 0;
            }
            return newIndex;
          });
          return [true];
        }}>
        {({ remainingTime, animatedColor }) => (
          <Animated.Text style={{ color: animatedColor, fontSize: 40 }}>
            {remainingTime}
          </Animated.Text>
        )}
      </CountdownCircleTimer>
      <Button
        title="Toggle Playing"
        onPress={() => setIsPlaying((prev) => !prev)}
      />
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    backgroundColor: '#ecf0f1',
    padding: 8,
  },
  paragraph: {
    margin: 24,
    fontSize: 18,
    fontWeight: 'bold',
    textAlign: 'center',
  },
});

演示

© www.soinside.com 2019 - 2024. All rights reserved.