You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();
}

逻辑说明

  1. 视频尺寸监听:在onVideoSizeChanged中获取视频的真实宽高,这是计算的基础。
  2. 视口尺寸监听:通过OnLayoutChangeListener捕获横竖屏切换后的容器尺寸变化,确保每次布局改变都重新计算。
  3. 比例判断:
    • 先计算FIT模式下视频的显示尺寸,判断该尺寸是否小于视口。
    • 如果视频显示尺寸小于视口,说明视频本身更小,用RESIZE_MODE_ZOOM放大至填满视口(超出部分裁剪)。
    • 如果视频显示尺寸等于或大于视口,说明视频本身更大,用RESIZE_MODE_FIT缩小至完全显示在视口内(无裁剪,可能留黑边)。

注意事项

  • 确保PlayerView的父容器(你的FrameLayout)是全屏或你期望的视口大小,否则计算会出现偏差。
  • 视频加载前无法获取尺寸,此时可以默认使用RESIZE_MODE_FIT,待视频加载完成后自动切换。

内容的提问来源于stack exchange,提问作者William Miranda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 13:30:42