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
相关产品推荐
相关产品推荐

