Android Kotlin中ExoPlayer画中画及Navigation Component实现方案咨询
如何在Android Kotlin中为ExoPlayer创建画中画(Pip)功能?
1. 配置Manifest与Activity属性
首先在AndroidManifest.xml中为播放页面的Activity添加画中画支持,同时配置配置变更参数避免Activity重建:
<activity android:name=".PlayerActivity" android:supportsPictureInPicture="true" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" />
2. 初始化ExoPlayer并处理画中画逻辑
在Activity中完成ExoPlayer初始化,添加进入画中画的触发逻辑,并监听画中画状态切换:
class PlayerActivity : AppCompatActivity() { private lateinit var player: ExoPlayer private var isInPipMode = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_player) // 初始化ExoPlayer player = ExoPlayer.Builder(this).build() val playerView = findViewById<PlayerView>(R.id.player_view) playerView.player = player // 设置播放源(替换为实际视频地址) val mediaItem = MediaItem.fromUri("https://example.com/video.mp4") player.setMediaItem(mediaItem) player.prepare() player.play() // 触发进入画中画 findViewById<Button>(R.id.enter_pip_btn).setOnClickListener { enterPictureInPictureMode() } } override fun onPictureInPictureModeChanged( isInPictureInPictureMode: Boolean, newConfig: Configuration? ) { super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig) isInPipMode = isInPictureInPictureMode // 画中画状态下隐藏播放控制器 val playerView = findViewById<PlayerView>(R.id.player_view) playerView.useController = !isInPictureInPictureMode } override fun onDestroy() { super.onDestroy() player.release() } }
Navigation Component基于单Activity多Fragment架构,核心是确保画中画状态下宿主Activity不被销毁,同时适配Fragment的显示逻辑。
1. 配置宿主Activity
和第一个问题一致,在AndroidManifest.xml中为宿主Activity添加画中画支持:
<activity android:name=".MainActivity" android:supportsPictureInPicture="true" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" />
2. 宿主Activity处理画中画与Navigation联动
class MainActivity : AppCompatActivity() { private lateinit var navController: NavController private var isInPipMode = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) navController = findNavController(R.id.nav_host_fragment) val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav) bottomNav.setupWithNavController(navController) } override fun onPictureInPictureModeChanged( isInPictureInPictureMode: Boolean, newConfig: Configuration? ) { super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig) isInPipMode = isInPictureInPictureMode // 画中画状态下隐藏底部导航栏 val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav) bottomNav.visibility = if (isInPictureInPictureMode) View.GONE else View.VISIBLE // 若当前不在播放Fragment,自动切换到播放Fragment val currentDestId = navController.currentDestination?.id if (isInPictureInPictureMode && currentDestId != R.id.playerFragment) { navController.navigate(R.id.playerFragment) } } // 画中画状态下返回不关闭应用,而是退出画中画 override fun onBackPressed() { if (isInPipMode) { exitPictureInPictureMode() } else { super.onBackPressed() } } // 用户切换到其他应用时,若当前在播放Fragment则自动进入画中画 override fun onUserLeaveHint() { super.onUserLeaveHint() val currentDestId = navController.currentDestination?.id if (currentDestId == R.id.playerFragment && !isInPipMode) { enterPictureInPictureMode() } } }
3. 播放Fragment中的ExoPlayer逻辑
class PlayerFragment : Fragment() { private lateinit var player: ExoPlayer private var isPlayerStarted = false override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.fragment_player, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 初始化ExoPlayer player = ExoPlayer.Builder(requireContext()).build() val playerView = view.findViewById<PlayerView>(R.id.player_view) playerView.player = player // 设置播放源 val mediaItem = MediaItem.fromUri("https://example.com/video.mp4") player.setMediaItem(mediaItem) player.prepare() // 手动触发进入画中画 view.findViewById<Button>(R.id.enter_pip_btn).setOnClickListener { requireActivity().enterPictureInPictureMode() } } override fun onStart() { super.onStart() if (isPlayerStarted) player.play() } override fun onPause() { super.onPause() isPlayerStarted = player.isPlaying player.pause() } override fun onDestroyView() { super.onDestroyView() player.release() } }
内容的提问来源于stack exchange,提问作者Mohammad Javad Habibpour
相关产品推荐
相关产品推荐

