限时福利领取


在Android音视频开发中,ExoPlayer作为Google推荐的媒体播放库,虽然功能强大,但默认的PlayerControlView进度条往往难以满足产品高度定制化的需求。今天我们就来聊聊如何实现一个既美观又实用的自定义进度条。

为什么需要自定义进度条?

默认进度条在复杂业务场景下会遇到几个典型问题:

  • 品牌UI适配困难:默认样式与App设计语言不匹配
  • 功能扩展性差:无法添加缓冲进度、章节标记等元素
  • 手势冲突:双指缩放、长按快进等操作需要特殊处理

默认进度条与自定义进度条对比

技术方案选型

通常有两种实现路径:

  1. 继承CustomView:完全重写绘制逻辑,灵活性最高但开发成本大
  2. 扩展PlayerControlView:复用现有功能,通过组合方式添加自定义组件

推荐第二种方案,既能利用ExoPlayer原生功能,又能快速实现UI定制。

核心实现步骤

1. 自定义ProgressBar样式

首先在XML中定义进度条样式:

<com.example.SegmentProgressBar
    android:layout_width="match_parent"
    android:layout_height="4dp"
    app:progressColor="@color/brand_primary"
    app:secondaryProgressColor="@color/buffer_blue"
    app:thumb="@drawable/custom_thumb" />

2. 注入自定义组件

通过addView()将组件添加到控制栏:

playerControlView.apply {
    removeView(defaultProgressBar)
    addView(customProgressBar, LayoutParams.MATCH_PARENT, 16.dpToPx())
}

3. 处理高级交互

重写onTouchEvent实现手势控制:

override fun onTouchEvent(event: MotionEvent): Boolean {
    when (event.actionMasked) {
        MotionEvent.ACTION_POINTER_DOWN -> {
            if (event.pointerCount == 2) {
                // 双指缩放处理
                scaleGestureDetector.onTouchEvent(event)
                return true
            }
        }
    }
    return super.onTouchEvent(event)
}

关键代码实现

进度同步监听器

player.addListener(object : Player.EventListener {
    override fun onPositionDiscontinuity(reason: Int) {
        updateProgressWithAnimation() // 带动画的进度更新
    }

    override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters) {
        adjustProgressUpdateSpeed(playbackParameters.speed)
    }
})

缓冲进度显示

override fun onDraw(canvas: Canvas) {
    // 绘制缓冲进度
    bufferRect.set(0f, 0f, width * bufferedPercentage, height.toFloat())
    canvas.drawRect(bufferRect, bufferPaint)

    // 绘制当前进度
    progressRect.set(0f, 0f, width * progressPercentage, height.toFloat())
    canvas.drawRect(progressRect, progressPaint)
}

自定义进度条效果

性能优化技巧

  1. 避免UI卡顿
  2. 使用Choreographer替代定时器更新进度
  3. 直播场景降低更新频率(如500ms/次)

  4. 内存优化

  5. 复用Bitmap对象避免频繁GC
  6. 使用canvas.clipRect()减少绘制区域

常见问题解决方案

  • Android版本差异
  • API 21以下需要关闭硬件加速避免绘制异常
  • 不同DPI设备注意thumb尺寸适配

  • 直播流特殊处理

  • 隐藏进度条thumb
  • 禁用拖拽seek功能

扩展思考

尝试实现带章节标记的智能进度条:

  1. 通过Timeline获取章节信息
  2. 在进度条下方绘制章节标记
  3. 点击章节标记跳转对应位置
fun drawChapterMarkers(canvas: Canvas) {
    timeline.periods.forEach { period ->
        val position = period.positionInWindowMs.toFloat() / duration
        canvas.drawCircle(width * position, height / 2f, 4.dpToPx(), chapterPaint)
    }
}

经过这一系列优化,我们的进度条不仅颜值在线,还能应对各种复杂场景。下次产品经理再提进度条需求时,你就能从容应对了!

Logo

音视频技术社区,一个全球开发者共同探讨、分享、学习音视频技术的平台,加入我们,与全球开发者一起创造更加优秀的音视频产品!

更多推荐