View版及更多功能使用:详见
一、概念
1.1 实现方式选择
| media3-ui-compose | media3-ui-compose-material3 | |
| 界面组件 | 基础组件。 | 开箱即用,含预设样式的按钮或控件。 |
| 状态管理 | 提供 remember***State 状态持有者来管理逻辑。 | 在内部管理状态,但仍可根据需要访问状态容器。 |
| 使用场景 | 使用自定义风格构建播放器界面。 | 使用 Material3 预设快速构建。 |
1.2 显示组件
| ContentFrame | @Composable 参数 contentScale:视频缩放。 参数 keepContentOnReset:为 true 播放器重置时将保持最后一帧画面显示,为 false 则会清空渲染表面。 参数 shutter:用于在需要覆盖视频渲染表面时显示。默认情况下,它显示为黑色背景。 |
1.3 控制组件
组件中可以直接拿到对应状态里的属性/方法(推荐通过this调用方便阅读)。
| 通用组件 | PlayPauseButton | 播放和暂停。 |
| SeekBackButton | 根据预设值,向前调整播放进度。 | |
| SeekForwardButton | 根据预设值,向后调整播放进度。 | |
| NextButton | 跳转到下一个媒体项。 | |
| PreviousButton | 跳转到上一个媒体项。 | |
| RepeatButton | 切换重复模式。 | |
| ShuffleButton | 切换随机模式。 | |
| MuteButton | 切换静音模式。 | |
| TimeText | 显示时长相关文本。 | |
| Material3 | PositionAndDurationText | 当前位置和总时长的文本。 |
| PositionText | 当前位置的文本。 | |
| DurationText | 总时长的文本。 | |
| RemainingDurationText | 剩余时长的文本。 |
自定义方式:
PlayPauseButton(player) { Icon( modifier = Modifier .size(20.dp) .clickable( enabled = this.isEnabled, onClick = { this.onClick() } ), imageVector = if (this.showPlay) Icons.Default.PlayArrow else Icons.Default.PauseCircle, contentDescription = if (this.showPlay) "Play" else "Pause" ) }Material3 方式:
Row { SeekBackButton(player) PlayPauseButton(player) SeekForwardButton(player) }1.4 状态(自定义控制组件)
如果上面没有需要的组件,可以自行通过状态来构建自定义组件。
| 状态 | 获取方式 |
| 播放暂停 | rememberPlayPauseButtonState |
| 上一项 | rememberPreviousButtonState |
| 下一项 | rememberNextButtonState |
| 重复模式 | rememberRepeatButtonState |
| 随机模式 | rememberShuffleButtonState |
| 播放速度 | rememberPlaybackSpeedState |
val state = rememberPlayPauseButtonState(player) Icon( modifier = Modifier .size(20.dp) .clickable( enabled = state.isEnabled, onClick = { state.onClick() } ), imageVector = if (state.showPlay) Icons.Default.PlayArrow else Icons.Default.PauseCircle, contentDescription = if (state.showPlay) "Play" else "Pause" )二、添加依赖
最新版本
[versions] media3 = "1.9.0" [libraries] media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "media3" } media3-datasource-okhttp = { module = "androidx.media3:media3-datasource-okhttp", version.ref = "media3" } #二选一 media3-ui-compose = { module = "androidx.media3:media3-ui-compose", version.ref = "media3" } media3-ui-compose-material3 = { moudle = "androidx.media3:media3-ui-compose-material3", version.ref = "media3" }三、实现方式
3.1 ViewModel
在 ViewModel 中提供 ExoPlayer,将业务和UI分离。
class PlayerVM : ViewModel() { private val playlist = mutableListOf<MediaItem>() private val playerListener by lazy { object : Player.Listener { } } val player by lazy { ExoPlayer.Builder(APP.context) .setSeekBackIncrementMs(10000) .setSeekForwardIncrementMs(10000) .build() .apply { addListener(playerListener) setMediaItem(MediaItem.fromUri("https://www.w3schools.com/html/movie.mp4")) prepare() playWhenReady = true } } override fun onCleared() { super.onCleared() player.release() } }3.2 UI
@Composable private fun Demo( viewModel: PlayerVM = viewModel() ) { ContentFrame(viewModel.player) }