全局锁定竖屏的App中,如何单独旋转ExoPlayer播放框架?
嘿,我之前刚好处理过一模一样的需求,给你分享两个靠谱的实现方案,亲测有效:
方案一:直接旋转ExoPlayer控件(最快捷)
这个思路很直接——既然整个App固定竖屏,那我们就只旋转ExoPlayer的播放视图,同时调整布局让它占满屏幕,隐藏其他无关UI。
步骤拆解:
- 监听全屏按钮点击,切换播放视图的旋转状态
- 调整布局参数,横屏时让播放器占满整个屏幕,竖屏时恢复原尺寸
- 修正触摸坐标(可选但重要),因为旋转后触摸点会和实际控件位置错位
代码示例(Kotlin):
// 假设playerView是你的ExoPlayer容器,otherViewGroup是页面其他UI区域 private var isFullScreen = false fun togglePlayerFullScreen() { isFullScreen = !isFullScreen if (isFullScreen) { // 旋转播放器到横屏角度(90度),加个动画更流畅 playerView.animate().rotation(90f).setDuration(300).start() // 隐藏其他UI,让播放器占满屏幕 otherViewGroup.visibility = View.GONE playerView.layoutParams = FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT ) // 隐藏系统状态栏和导航栏,提升沉浸感 hideSystemUI() } else { // 切回竖屏状态 playerView.animate().rotation(0f).setDuration(300).start() // 恢复原布局和UI显示 otherViewGroup.visibility = View.VISIBLE playerView.layoutParams = LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, resources.getDimensionPixelSize(R.dimen.default_player_height) ) // 显示系统UI showSystemUI() } } // 处理系统UI显示/隐藏 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) } private fun showSystemUI() { window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE }
修复触摸错位问题:
旋转后,触摸事件的坐标会和控件实际位置不匹配,需要重写触摸监听转换坐标:
playerView.setOnTouchListener { v, event -> if (isFullScreen) { // 旋转90度后,x和y坐标需要互换并调整 val rotatedX = event.y val rotatedY = v.width - event.x val correctedEvent = MotionEvent.obtain( event.downTime, event.eventTime, event.action, rotatedX, rotatedY, event.metaState ) val result = v.onTouchEvent(correctedEvent) correctedEvent.recycle() return@setOnTouchListener result } v.onTouchEvent(event) }
方案二:用TextureView手动控制视频渲染(更灵活)
如果需要更精细地控制视频的缩放和旋转,可以用TextureView作为ExoPlayer的渲染载体,通过ExoPlayer的视频尺寸回调来调整渲染参数。
步骤拆解:
- 给PlayerView设置自定义的TextureView
- 监听ExoPlayer的视频尺寸变化,动态调整TextureView的旋转、缩放比例
- 同样配合布局调整和系统UI控制实现全屏效果
代码示例:
// 初始化时设置TextureView val textureView = TextureView(context) playerView.setVideoTextureView(textureView) // 监听视频尺寸变化,调整渲染参数 player.addListener(object : Player.Listener { override fun onVideoSizeChanged(videoSize: VideoSize) { super.onVideoSizeChanged(videoSize) if (isFullScreen) { // 横屏时旋转TextureView textureView.rotation = 90f // 计算缩放比例,让视频铺满屏幕 val screenHeight = resources.displayMetrics.heightPixels.toFloat() val screenWidth = resources.displayMetrics.widthPixels.toFloat() val scaleX = screenHeight / videoSize.height val scaleY = screenWidth / videoSize.width val scale = max(scaleX, scaleY) textureView.scaleX = scale textureView.scaleY = scale } else { // 竖屏时恢复默认状态 textureView.rotation = 0f val scaleX = resources.displayMetrics.widthPixels.toFloat() / videoSize.width val scaleY = playerView.height.toFloat() / videoSize.height val scale = min(scaleX, scaleY) textureView.scaleX = scale textureView.scaleY = scale } } }) // 全屏切换逻辑和方案一一致,这里省略重复代码
注意事项
- 确保你的App已经在Manifest里固定了竖屏:
android:screenOrientation="portrait" - 如果使用SurfaceView,旋转后可能会有画面闪烁问题,TextureView的兼容性更好,但性能略逊于SurfaceView,可以根据需求选择
- 横屏时记得处理返回键逻辑,点击返回键要切回竖屏状态
内容的提问来源于stack exchange,提问作者Alireza Ghanbarinia
相关产品推荐
相关产品推荐

