You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为react-native-video构建自定义进度条?求推荐适用库

自定义react-native-video进度条实现方案&推荐库

嘿,我来帮你搞定react-native-video的自定义进度条问题!分两种方式:自己手动撸一个(完全可控),或者用现成的库(省时间),都给你讲清楚。

一、手动实现自定义进度条

如果想要完全定制样式和交互逻辑,手动实现是最好的选择,步骤很清晰:

1. 核心准备工作

首先确保你已经安装了react-native-video:

npm install react-native-video
# 或者用yarn
yarn add react-native-video

2. 完整代码示例

下面是一个可直接复用的自定义播放器+进度条组件,包含了播放时间显示、拖拽跳转功能:

import React, { useState, useRef } from 'react';
import { View, TouchableOpacity, StyleSheet, Text } from 'react-native';
import Video from 'react-native-video';

const CustomVideoPlayer = () => {
  const videoRef = useRef(null);
  const [currentTime, setCurrentTime] = useState(0);
  const [duration, setDuration] = useState(0);
  const [isSeeking, setIsSeeking] = useState(false);

  // 把秒数格式化成 MM:SS 格式
  const formatTime = (seconds) => {
    const mins = Math.floor(seconds / 60);
    const secs = Math.floor(seconds % 60);
    return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
  };

  // 视频加载完成时获取总时长
  const handleLoad = (data) => {
    setDuration(data.duration);
  };

  // 实时更新当前播放时间(拖拽时暂停自动更新)
  const handleProgress = (data) => {
    if (!isSeeking) {
      setCurrentTime(data.currentTime);
    }
  };

  // 根据触摸位置计算要跳转的时间
  const calculateSeekTime = (e) => {
    const barWidth = e.nativeEvent.target.width;
    const touchX = e.nativeEvent.locationX;
    const seekRatio = touchX / barWidth;
    return seekRatio * duration;
  };

  // 开始拖拽:标记状态+跳转视频
  const handleSeekStart = (e) => {
    setIsSeeking(true);
    const seekTime = calculateSeekTime(e);
    videoRef.current.seek(seekTime);
    setCurrentTime(seekTime);
  };

  // 拖拽中:只更新显示的时间
  const handleSeekMove = (e) => {
    const seekTime = calculateSeekTime(e);
    setCurrentTime(seekTime);
  };

  // 结束拖拽:完成跳转+恢复自动更新
  const handleSeekEnd = (e) => {
    const seekTime = calculateSeekTime(e);
    videoRef.current.seek(seekTime);
    setCurrentTime(seekTime);
    setIsSeeking(false);
  };

  // 计算进度百分比
  const progressPercent = duration > 0 ? (currentTime / duration) * 100 : 0;

  return (
    <View style={styles.container}>
      {/* 视频组件 */}
      <Video
        ref={videoRef}
        source={{ uri: 'https://example.com/your-video.mp4' }} // 替换成你的视频地址
        style={styles.video}
        onLoad={handleLoad}
        onProgress={handleProgress}
        controls={false} // 关闭原生控件,用自定义的
        resizeMode="contain"
      />

      {/* 自定义进度条区域 */}
      <View style={styles.progressContainer}>
        <Text style={styles.timeText}>{formatTime(currentTime)}</Text>
        <TouchableOpacity
          style={styles.progressBar}
          onTouchStart={handleSeekStart}
          onTouchMove={handleSeekMove}
          onTouchEnd={handleSeekEnd}
        >
          {/* 已播放的进度条部分 */}
          <View style={[styles.progressFilled, { width: `${progressPercent}%` }]} />
          {/* 可拖拽的滑块 */}
          <View style={[styles.progressHandle, { left: `${progressPercent}%` }]} />
        </TouchableOpacity>
        <Text style={styles.timeText}>{formatTime(duration)}</Text>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#fff',
  },
  video: {
    width: '100%',
    height: 280,
  },
  progressContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    width: '90%',
    marginTop: 15,
    gap: 10,
  },
  timeText: {
    fontSize: 12,
    color: '#555',
    width: 55,
    textAlign: 'center',
  },
  progressBar: {
    flex: 1,
    height: 6,
    backgroundColor: '#e5e5e5',
    borderRadius: 3,
    position: 'relative',
    overflow: 'hidden',
  },
  progressFilled: {
    height: '100%',
    backgroundColor: '#2563eb',
    borderRadius: 3,
  },
  progressHandle: {
    position: 'absolute',
    top: -5,
    width: 16,
    height: 16,
    backgroundColor: '#2563eb',
    borderRadius: 8,
    transform: [{ translateX: -8 }], // 让滑块居中在进度末端
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.2,
  },
});

export default CustomVideoPlayer;

3. 关键逻辑解释

  • 获取视频状态:通过onLoad拿到视频总时长,onProgress实时获取当前播放时间;
  • 拖拽交互:用isSeeking标记拖拽状态,避免自动更新和手动拖拽的时间冲突;
  • 时间计算:根据触摸点在进度条的比例,换算成对应的视频时间,调用videoRef.current.seek()完成跳转;
  • 样式自定义:通过修改styles里的属性,你可以轻松调整进度条的颜色、滑块形状、大小等。

二、推荐的第三方开发库

如果不想从零写,这些现成的库能帮你快速实现需求,还自带很多实用功能:

  • react-native-video-controls:最常用的react-native-video配套UI库,自带完整的播放器控件(进度条、播放/暂停、音量、全屏),支持高度自定义。你可以直接用默认样式,也能通过props覆盖进度条颜色、滑块样式,甚至替换整个控件组件。安装命令:

    npm install react-native-video-controls
    
  • @react-native-community/slider:轻量专业的滑块组件,专门处理拖拽选择场景。你可以把它和react-native-video结合,自己组装进度条逻辑,灵活性极高。支持自定义轨道颜色、滑块样式、最小/最大值,完美适配视频进度需求。安装命令:

    npm install @react-native-community/slider
    
  • react-native-progress:提供多种进度指示器(线性、圆形、环形等),其中的Progress.Bar可以直接用来做视频进度条,配合视频的时间数据就能快速实现,样式自定义也很简单。安装命令:

    npm install react-native-progress
    

内容的提问来源于stack exchange,提问作者Cya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:57:22