【问题标题】:How to reset controlTimeout in react-native-video ref如何在 react-native-video ref 中重置 controlTimeout
【发布时间】:2022-01-03 03:01:30
【问题描述】:

我有一个使用 react-native-video-controls 的视频组件,除了一件事之外一切都很好:

我用来跳过/查找和播放/暂停的自定义按钮不会重置 controlTimeout 值(上次交互与显示/隐藏视频控件的 hideControls 操作之间的延迟。从这个意义上说,无论如何多次按下我的按钮,超时只会倒计时并消失,而不是在每次按下时重置。

我应该能够连续按下按钮以无限期地保持控件开启(只要计时器没有达到限制)。如何重置 controlTimeout 值?

我的视频组件:

import React, { useEffect, useRef, useState } from 'react';
import { VideoProperties } from 'react-native-video';
import Video from 'react-native-video-controls';
import { Animated, StyleSheet, Text, View } from 'react-native';
import { Image } from 'react-native-elements';
import { colors } from '../styles/colorPalette';
import { TouchableOpacity } from 'react-native-gesture-handler';
import { useTheme } from '../contexts/ThemeContext';
import { ReactNativeProps } from 'react-native-render-html';
import { useIsFocused } from '@react-navigation/native';

interface VideoPlayerProps extends VideoProperties {
  autoPlay?: boolean
  categoryOverlay?: boolean | string
  disableSeekSkip?: boolean
  ref?: any
}

const VideoPlayer = (props: VideoPlayerProps & ReactNativeProps) => {
  const [vidAspectRatio, setVidAspectRatio] = useState(1.75)
  const [duration, setDuration] = useState(null);
  const [error, setError] = useState(null)
  const [lastTouched, setLastTouched] = useState(0)
  const [progress, setProgress] = useState(1);
  const [isPlaying, setIsPlaying] = useState(!props.paused || false);
  const [controlsActive, setControlsActive] = useState(false);
  const { darkMode } = useTheme();
  const { categoryOverlay, disableSeekSkip = false, source } = props;
  const isFocused = useIsFocused();
  const videoRef = useRef<Video>(null);

  const handleError = (e: any) => {
    console.log("ERROR: ", e)
  }

  const handleSeek = (num: number) => {
    if (!videoRef.current || videoRef.current.state.seeking === true || (Date.now() - lastTouched < 250)) {
      return
    } else {
    videoRef.current.player.ref.seek(Math.max(0, Math.min((videoRef.current.state.currentTime + num), videoRef.current.state.duration)))
    setLastTouched(Date.now())
    }
  }

  const handleHeight = (res: any) => {
    // set height and duration
    duration && setDuration(res.duration ?? null);
    setVidAspectRatio(res.naturalSize ? (res.naturalSize.width / res.naturalSize.height) : 1.75);
  }

  const handlePause = (res: any) => {
    // The logic to handle the pause/play logic
    res.playbackRate === 0 ? setIsPlaying(false) : setIsPlaying(true);
  }

  const handlePlayPausePress = () => {
    isPlaying ? setIsPlaying(false) : setIsPlaying(true)
  }

  const handleProgress = (progress: any) => {
    setProgress(progress.atValue);
  }

  const handleSetControlsActive = (active: boolean) => {
    setControlsActive(active)
  }

  const styles = StyleSheet.create({
    container: {
      position: 'relative',
      resizeMode: 'cover',
      aspectRatio: vidAspectRatio ? vidAspectRatio : 1.75,
      justifyContent: 'center',
      alignItems: 'center',
    },
    controls: {
    },
    controlsImage: {
      resizeMode: 'contain',
      width: '100%',
    },
    playIcon: {
      color: darkMode ? colors.primary.purple4 : "#fff",
      fontSize: 30,
      marginHorizontal: 30,
    },
    playIconContainer: {
      flexDirection: 'row',
      justifyContent: 'space-around',
      alignItems: 'center',
      paddingHorizontal: 15,
      paddingVertical: 7.5,
      borderRadius: 10,
    },
    video: {
      position: 'absolute',
      top: 0,
      bottom: 0,
      left: 0,
      right: 0,
    },
    videoPlayer: {
      position: 'absolute',
      height: '100%',
      width: '100%',
    },
    videoPoster: {
      position: 'absolute',
      top: 0,
      bottom: 0,
      left: 0,
      right: 0,
      resizeMode: 'cover',
    },
    videoWrapper: {
      position: 'absolute',
      width: '100%',
      height: '100%',
    },
    volumeOverlay: {
      position: 'absolute',
      top: 0,
      right: 0,
    },
    categoryOverlay: {
      paddingHorizontal: 10,
      paddingVertical: 5,
      position: 'absolute',
      color: '#fff',
      bottom: 10,
      right: 10,
      backgroundColor: 'rgba(0,0,0, .75)',
      borderRadius: 10,
      zIndex: 999,
      textTransform: 'uppercase',
    },
  });

  const convertTime = (seconds: number) => {
    const secsRemaining = Math.floor(seconds % 60);
    return `${Math.floor(seconds / 60)}:${secsRemaining < 10 ? '0' + secsRemaining : secsRemaining}`
  }

  const convertTimeV2 = (secs: number) => {
    var hours   = Math.floor(secs / 3600)
    var minutes = Math.floor(secs / 60) % 60
    var seconds = Math.floor(secs % 60)

    return [hours,minutes,seconds]
        .map(v => v < 10 ? "0" + v : v)
        .filter((v,i) => v !== "00" || i > 0)
        .join(":")
  }

  useEffect(() => {
    if (error) console.log("ERROR", error)
  }, [error])
  
  return (
    <Animated.View  style={styles.container}>
      { (controlsActive || !isPlaying) && 
        <View style={styles.volumeOverlay}>
          <Image containerStyle={{height: 60, width: 60}} source={videoRef.current.state.muted ? require('../assets/icons/Miscellaneous/Video_Controls/volume-muted.png') : require('../assets/icons/Miscellaneous/Video_Controls/volume-on.png') }/>
        </View>
      }
      <View style={styles.videoWrapper}>
        <Video
          ref={videoRef}
          // controls={Platform.OS === 'ios' ? true : false} /* Added Platform flag to circumvent iOS control bug for now */
          {...props}
          source={source}
          showOnStart
          disableBack
          disableFullscreen
          disablePlayPause
          disableSeekbar={disableSeekSkip}
          disableTimer={disableSeekSkip}
          paused={(!isPlaying || !isFocused) || props.paused}
          onLoad={handleHeight}
          onError={handleError}
          onHideControls={() => handleSetControlsActive(false)}
          onShowControls={() => handleSetControlsActive(true)}
          onPlaybackRateChange={handlePause}
          onProgress={handleProgress}
          seekColor="#a146b7" 
          controlTimeout={3000}
          style={{flex: 1, flexGrow: 1}}
          containerStyle={{flex: 1, flexGrow: 1}}
        />
      </View>
      {categoryOverlay && progress === 1 && 
        <View style={styles.categoryOverlay}>
          <Text style={{color: "#fff", textTransform: 'uppercase'}}>{(typeof categoryOverlay === 'boolean') && duration ? convertTime(duration) : categoryOverlay}</Text>
        </View>
      }
      { (progress === 1 && !isPlaying) && <View style={styles.videoPoster}><Image style={{width: '100%', height: '100%', resizeMode: 'contain'}} source={{ uri: `https://home.test.com${props.poster}` }} /></View> }
      { (controlsActive || !isPlaying) && 
        <View style={styles.playIconContainer}>
          { !disableSeekSkip && <TouchableOpacity disabled={videoRef.current.state.currentTime == 0 || videoRef.current.state.seeking} onPress={() => handleSeek(-15)}>
            <Image containerStyle={{height: 60, width: 60}} style={styles.controlsImage} source={require('../assets/icons/Miscellaneous/Video_Controls/back-15s.png')}/>
          </TouchableOpacity> }
          <TouchableOpacity onPress={handlePlayPausePress}>
            <Image containerStyle={{height: 60, width: 60}} source={isPlaying ? require('../assets/icons/Miscellaneous/Video_Controls/pause-video-white.png') : require('../assets/icons/Miscellaneous/Video_Controls/play-video-white.png')}/>
          </TouchableOpacity>
          { !disableSeekSkip && <TouchableOpacity disabled={videoRef.current.state.currentTime == videoRef.current.state.duration || videoRef.current.state.seeking} onPress={() => handleSeek(15)}>
            <Image containerStyle={{height: 60, width: 60}} style={styles.controlsImage} source={require('../assets/icons/Miscellaneous/Video_Controls/skip-15s.png')}/>
          </TouchableOpacity> }
        </View> }
    </Animated.View>
  );
}

export default React.memo(VideoPlayer)

【问题讨论】:

  • 您能否提供一些代码,以便任何人都能更好地理解您的问题。
  • 我认为这更像是一个一般性的“你知道吗”问题 - 但如果有帮助,我已经添加了代码。 videoRef(ref)中有一个名为 player.controlTimeout 的道具,它增加一个计时器,如果超过阈值则清除控件。当我的自定义按钮被按下时,它们不会重置计时器,因此即使在点击后控件仍会关闭。

标签: react-native react-native-video


【解决方案1】:

这是一个棘手的解决方案,但您可以删除/编辑/实现代码 react-native-video-controls/VideoPlayer.js 在代码中找到相关部分(从第 336 行开始)并关注setControlTimeoutclearControlTimeoutresetControlTimeoutclearTimeout。也许您可以直接在自定义按钮中使用它们。

【讨论】:

  • 就是这样。我在 VideoiPlayer.js 中看到了 clearTimeout 函数以及 resetTImeout 函数。我只是不知道如何从 ref 中调用它。它没有暴露。我只是觉得很奇怪,当您添加自定义按钮时,您无法使用它。 ://
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-14
  • 1970-01-01
  • 2017-09-16
  • 1970-01-01
  • 1970-01-01
  • 2022-11-04
相关资源
最近更新 更多