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

ExoPlayer多分段视频进度条咨询:总进度条与多分段进度条

ExoPlayer播放分段视频:全局进度条与分段进度条实现方案

一、实现全局播放进度条(显示总时长+全局进度)

1. 计算播放列表总时长

ExoPlayer不会自动返回整个播放列表的总时长,需要手动累加所有媒体项的时长。注意必须等媒体元数据加载完成后再计算,否则会拿到无效的C.TIME_UNSET值:

// 监听媒体加载状态,确保能获取有效时长
exoPlayer.addListener(object : Player.Listener {
    override fun onMediaMetadataChanged(mediaMetadata: MediaMetadata) {
        super.onMediaMetadataChanged(mediaMetadata)
        calculateTotalDuration()
    }

    override fun onPlaybackStateChanged(playbackState: Int) {
        super.onPlaybackStateChanged(playbackState)
        if (playbackState == Player.STATE_READY) {
            calculateTotalDuration()
        }
    }
})

// 累加所有媒体项时长得到总时长
private fun calculateTotalDuration(): Long {
    var totalDuration = 0L
    for (i in 0 until exoPlayer.mediaItemCount) {
        val duration = exoPlayer.getDuration(i)
        if (duration != C.TIME_UNSET) {
            totalDuration += duration
        }
    }
    // 拿到总时长后更新UI显示
    updateGlobalProgressBarTotal(totalDuration)
    return totalDuration
}

2. 实时计算全局播放位置

全局播放位置 = 已播放完成的所有前置媒体项总时长 + 当前媒体项的已播放时长,通过定时监听播放进度来更新:

// 启动进度定时更新(每秒一次)
private fun startGlobalProgressUpdate() {
    val handler = Handler(Looper.getMainLooper())
    handler.post(object : Runnable {
        override fun run() {
            if (exoPlayer.isPlaying) {
                updateGlobalProgress()
                handler.postDelayed(this, 1000)
            }
        }
    })
}

private fun updateGlobalProgress() {
    val currentIndex = exoPlayer.currentMediaItemIndex
    // 计算前置已播放媒体的总时长
    var playedBeforeCurrent = 0L
    for (i in 0 until currentIndex) {
        val duration = exoPlayer.getDuration(i)
        if (duration != C.TIME_UNSET) {
            playedBeforeCurrent += duration
        }
    }
    // 全局播放位置
    val globalPosition = playedBeforeCurrent + exoPlayer.currentPosition
    val totalDuration = calculateTotalDuration()
    // 更新自定义全局进度条
    globalProgressBar.max = totalDuration.toInt()
    globalProgressBar.progress = globalPosition.toInt()
}

二、实现横向组合的分段进度条

需要自定义UI容器,为每个视频片段单独创建进度条,按时长比例分配宽度,再根据播放状态更新各分段进度:

1. 布局容器示例

<LinearLayout
    android:id="@+id/segmentProgressContainer"
    android:layout_width="match_parent"
    android:layout_height="4dp"
    android:orientation="horizontal"
    android:weightSum="1"
    android:layout_marginTop="8dp"/>

2. 动态创建分段进度条

根据播放列表数量创建对应进度条,按片段时长占总时长的比例分配宽度:

private fun initSegmentProgressBars() {
    val totalDuration = calculateTotalDuration()
    if (totalDuration == 0L) return

    segmentProgressContainer.removeAllViews()
    for (i in 0 until exoPlayer.mediaItemCount) {
        val itemDuration = exoPlayer.getDuration(i)
        if (itemDuration == C.TIME_UNSET) continue

        val progressBar = ProgressBar(context).apply {
            layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT).apply {
                weight = itemDuration.toFloat() / totalDuration
                marginEnd = dpToPx(2)
            }
            max = itemDuration.toInt()
            progress = 0
            // 自定义进度条样式(可选)
            progressDrawable = resources.getDrawable(R.drawable.segment_progress_style, null)
        }
        segmentProgressContainer.addView(progressBar)
    }
}

// dp转px工具方法
private fun dpToPx(dp: Int): Int {
    return (dp * resources.displayMetrics.density).toInt()
}

3. 更新分段进度状态

在全局进度更新时,同步更新每个分段进度条的状态:

private fun updateSegmentProgressBars() {
    val currentIndex = exoPlayer.currentMediaItemIndex
    val currentItemPosition = exoPlayer.currentPosition

    for (i in 0 until segmentProgressContainer.childCount) {
        val progressBar = segmentProgressContainer.getChildAt(i) as ProgressBar
        val itemDuration = exoPlayer.getDuration(i)
        if (itemDuration == C.TIME_UNSET) continue

        when {
            // 已播放完成的片段,进度拉满
            i < currentIndex -> progressBar.progress = itemDuration.toInt()
            // 当前播放的片段,同步进度
            i == currentIndex -> progressBar.progress = currentItemPosition.toInt()
            // 未播放的片段,进度置0
            else -> progressBar.progress = 0
        }
    }
}

只需要在updateGlobalProgress()方法末尾调用updateSegmentProgressBars(),即可实现全局进度与分段进度的同步更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 09:55:58