求助:如何实现ExoPlayer在RecyclerView与ViewPager中的全屏播放
Hey there! I’ve been in your shoes before—adding fullscreen support to ExoPlayer when it’s nested in RecyclerView or ViewPager can feel tricky at first, but it’s totally doable with a few key steps. Let me walk you through how I’ve implemented it in similar projects:
Fullscreen playback essentially boils down to moving ExoPlayer's SurfaceView/TextureView from its original layout container to a full-screen container (like the Activity's DecorView), switching the screen orientation, and hiding system UI. When exiting fullscreen, you just reverse this process and restore the player's state.
1. Prepare Full-Screen Container & State Tracking
First, add a full-screen FrameLayout to your Activity's root layout (set it to GONE by default) to hold the player when in fullscreen:
<!-- Place this as the top-level view in your Activity layout --> <FrameLayout android:id="@+id/fullscreen_container" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="gone"/>
Then, track key player states to ensure seamless transition:
// Inside your custom player wrapper or Activity private var isFullscreen = false private var playbackPosition = 0L private var isPlaying = false private var originalParent: ViewGroup? = null private var originalLayoutParams: ViewGroup.LayoutParams? = null private lateinit var fullscreenContainer: FrameLayout
2. Implement Full-Screen Toggle Logic
Add a click listener to your custom controller's fullscreen button to trigger the switch:
fullscreenToggleBtn.setOnClickListener { if (isFullscreen) exitFullscreen() else enterFullscreen() }
Enter Fullscreen
private fun enterFullscreen() { isFullscreen = true // Save current playback state playbackPosition = exoPlayer.currentPosition isPlaying = exoPlayer.isPlaying exoPlayer.pause() // Get your player view (replace with your actual player view reference) val playerView = yourCustomPlayerView originalParent = playerView.parent as ViewGroup originalLayoutParams = playerView.layoutParams // Move player to fullscreen container originalParent?.removeView(playerView) fullscreenContainer.addView(playerView, FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT )) fullscreenContainer.visibility = View.VISIBLE // Switch to landscape orientation requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE // Hide system UI for immersive fullscreen hideSystemUI() // Resume playback exoPlayer.seekTo(playbackPosition) exoPlayer.playWhenReady = isPlaying }
Exit Fullscreen
private fun exitFullscreen() { isFullscreen = false // Save current playback state playbackPosition = exoPlayer.currentPosition isPlaying = exoPlayer.isPlaying exoPlayer.pause() // Move player back to original container val playerView = fullscreenContainer.getChildAt(0) as PlayerView fullscreenContainer.removeView(playerView) originalParent?.addView(playerView, originalLayoutParams) fullscreenContainer.visibility = View.GONE // Restore portrait orientation (or your default orientation) requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT // Show system UI showSystemUI() // Resume playback exoPlayer.seekTo(playbackPosition) exoPlayer.playWhenReady = isPlaying }
3. Handle System UI Visibility
Implement immersive fullscreen by hiding/showing status and navigation bars:
private fun hideSystemUI() { window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) window.statusBarColor = Color.TRANSPARENT window.navigationBarColor = Color.TRANSPARENT } private fun showSystemUI() { window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) window.statusBarColor = Color.BLACK // Replace with your app's default status bar color window.navigationBarColor = Color.BLACK }
4. Handle Screen Rotation & Lifecycle
Screen rotation will trigger Activity recreation, so save and restore state:
override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putBoolean("isFullscreen", isFullscreen) outState.putLong("playbackPosition", playbackPosition) outState.putBoolean("isPlaying", isPlaying) } override fun onRestoreInstanceState(savedInstanceState: Bundle) { super.onRestoreInstanceState(savedInstanceState) isFullscreen = savedInstanceState.getBoolean("isFullscreen") playbackPosition = savedInstanceState.getLong("playbackPosition") isPlaying = savedInstanceState.getBoolean("isPlaying") // Re-enter fullscreen if we were in that state before rotation if (isFullscreen) enterFullscreen() }
Extra Tips for RecyclerView/ViewPager
- Disable scrolling during fullscreen: Set
viewPager.isUserInputEnabled = falseorrecyclerView.layoutManager?.isScrollEnabled = falsewhen entering fullscreen, then re-enable on exit. - Player cleanup: When a RecyclerView item or ViewPager page is off-screen, pause and release the player to avoid memory leaks.
5. Final Polish
- Toggle the fullscreen button's icon (show "shrink" icon when in fullscreen, "expand" otherwise) for better UX.
- If using
PlayerView, leverage its built-in state management, but ensure your custom controller syncs with its state.
This approach works reliably across most use cases—I’ve used it in several apps with nested players. Adjust the code to fit your specific layout and player setup!
内容的提问来源于stack exchange,提问作者Ashkan

