ExoPlayer自适应视口缩放问题:如何按需切换缩放模式?
解决方案:动态切换ExoPlayer的ResizeMode
要实现根据视频尺寸和视口大小自动切换RESIZE_MODE_FIT和RESIZE_MODE_ZOOM,核心思路是监听视频尺寸变化+实时计算视口与视频的比例关系,动态调整缩放模式。
步骤1:配置Activity的横竖屏属性
首先确保Activity支持横竖屏切换且不重建,避免重复初始化播放器。在AndroidManifest.xml中给目标Activity添加:
<activity android:name=".YourVideoActivity" android:configChanges="orientation|screenSize|smallestScreenSize" android:screenOrientation="sensor" />
步骤2:实现动态ResizeMode切换逻辑
通过ExoPlayer的Player.Listener监听视频尺寸加载完成事件,同时监听布局变化(横竖屏切换时触发),实时计算并切换缩放模式。
示例代码:
private PlayerView playerView; private ExoPlayer exoPlayer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_video); playerView = findViewById(R.id.player_view); exoPlayer = new ExoPlayer.Builder(this).build(); playerView.setPlayer(exoPlayer); // 监听视频尺寸变化,触发缩放模式更新 exoPlayer.addListener(new Player.Listener() { @Override public void onVideoSizeChanged(VideoSize videoSize) { super.onVideoSizeChanged(videoSize); updatePlayerResizeMode(); } }); // 监听布局变化(横竖屏切换时容器尺寸改变) ViewGroup container = (ViewGroup) playerView.getParent(); container.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { if (exoPlayer.getVideoSize() != null) { updatePlayerResizeMode(); } }); // 准备播放视频(替换为你的视频源) MediaItem mediaItem = MediaItem.fromUri("your_video_url_here"); exoPlayer.setMediaItem(mediaItem); exoPlayer.prepare(); exoPlayer.play(); } private void updatePlayerResizeMode() { VideoSize videoSize = exoPlayer.getVideoSize(); if (videoSize == null || videoSize.width == 0 || videoSize.height == 0) { return; } ViewGroup container = (ViewGroup) playerView.getParent(); int viewWidth = container.getWidth(); int viewHeight = container.getHeight(); // 容器未完成测量时,延迟计算 if (viewWidth == 0 || viewHeight == 0) { container.post(this::updatePlayerResizeMode); return; } // 计算视频与视口的宽高比 float videoRatio = (float) videoSize.width / videoSize.height; float viewRatio = (float) viewWidth / viewHeight; // 计算FIT模式下视频的显示尺寸 float fitDisplayWidth, fitDisplayHeight; if (videoRatio > viewRatio) { fitDisplayWidth = viewWidth; fitDisplayHeight = fitDisplayWidth / videoRatio; } else { fitDisplayHeight = viewHeight; fitDisplayWidth = fitDisplayHeight * videoRatio; } // 判断:FIT模式下视频是否小于视口 → 是则用ZOOM放大填满,否则用FIT缩小显示 boolean isVideoSmallerThanViewport = fitDisplayWidth < viewWidth || fitDisplayHeight < viewHeight; if (isVideoSmallerThanViewport) { playerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_ZOOM); } else { playerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIT); } } @Override protected void onDestroy() { super.onDestroy(); exoPlayer.release(); }
逻辑说明
- 视频尺寸监听:在
onVideoSizeChanged中获取视频的真实宽高,这是计算的基础。 - 视口尺寸监听:通过
OnLayoutChangeListener捕获横竖屏切换后的容器尺寸变化,确保每次布局改变都重新计算。 - 比例判断:
- 先计算
FIT模式下视频的显示尺寸,判断该尺寸是否小于视口。 - 如果视频显示尺寸小于视口,说明视频本身更小,用
RESIZE_MODE_ZOOM放大至填满视口(超出部分裁剪)。 - 如果视频显示尺寸等于或大于视口,说明视频本身更大,用
RESIZE_MODE_FIT缩小至完全显示在视口内(无裁剪,可能留黑边)。
- 先计算
注意事项
- 确保PlayerView的父容器(你的FrameLayout)是全屏或你期望的视口大小,否则计算会出现偏差。
- 视频加载前无法获取尺寸,此时可以默认使用
RESIZE_MODE_FIT,待视频加载完成后自动切换。
内容的提问来源于stack exchange,提问作者William Miranda
相关产品推荐
相关产品推荐

