diff --git a/Assets/Scripts/UI/Components/VideoCtrl.cs b/Assets/Scripts/UI/Components/VideoCtrl.cs index 27c26ba..22d24c7 100644 --- a/Assets/Scripts/UI/Components/VideoCtrl.cs +++ b/Assets/Scripts/UI/Components/VideoCtrl.cs @@ -162,13 +162,41 @@ namespace Kill.UI.Components FitWindowAspect(windowImage, player.width / (float)Mathf.Max(1, (int)player.height)); if (needFullScreen) { - // 根据视频宽高比选择全屏UI:竖屏视频用竖屏全屏UI,否则用默认全屏UI + // ============================================================ + // 全屏视频适配经验总结(踩坑记录,避免后续重复犯错) + // ============================================================ + // 目标:完整显示视频、不变形;在不同设备宽高比下都让视频占屏幕比例最大化。 + // + // 1. UI 节点角色(场景已配置): + // - portraitFullImage:未旋转的 RawImage,专门用于竖屏视频 + // - fullImage:旋转了 -90° 的 RawImage,专门用于横屏视频(让 app 不旋转也能看横屏视频) + // - 选择规则:video 高>宽 → portraitFullImage;否则 → fullImage + // + // 2. 视觉屏幕 = 父 stretch 节点的实际 rect(手机屏幕真实宽高), + // 与子节点是否旋转无关。RectTransform 的 sizeDelta 在 UI 旋转 90° 后, + // (sizeDelta.x, sizeDelta.y) 视觉上变成 (sizeDelta.y, sizeDelta.x)。 + // + // 3. 视频长边贴齐策略(按视频/屏幕比例选边): + // 判定 = 视频短边占屏幕比 = 1/videoAspect vs 屏幕宽高比 + // - 1/videoAspect > 屏幕比 → 视频长边贴屏幕短边(视觉宽=parentW,留黑上下) + // 例:竖屏手机 750x1624 + 横屏视频 1.78 → 视觉=(750, 1335),sizeDelta=(1335, 750) + // - 1/videoAspect < 屏幕比 → 视频长边贴屏幕长边(视觉高=parentH,留黑左右) + // 例:接近正方形 1179x1600 + 横屏视频 1.78 → 视觉=(900, 1600),sizeDelta=(1600, 900) + // - 比例接近时(屏幕接近正方形)走"长边贴长边",让视频占用面积更大 + // + // 4. 常见错误: + // - 用 cover 模式裁切 UV:横屏视频在竖屏手机上会左右被裁,丢失画面 + // - 用 contain 让短边贴齐屏幕短边:在 750x1624 上视频会被压缩成窄长条 + // - frameAspect 写反:rotated90 时应该是 parentW/parentH 还是 parentH/parentW 要分清 + // - 视觉屏幕写成了 rotated90 ? parentH : parentW(错):视觉屏幕与旋转无关,始终是 parentW x parentH + // + // 5. UV 不动:使用 contain 不裁切即可,无需调整 uvRect + // ============================================================ currentFullImage = (player.width < player.height && portraitFullImage != null) ? portraitFullImage : fullImage; // 全屏纹理按视频分辨率创建,保证宽高比正确、不变形 RenderTexture fullTexture = new RenderTexture((int)player.width, (int)player.height, 1); renderTextures.Add(fullTexture); currentFullImage.texture = fullTexture; - // 显示区域铺满屏幕,保持视频比例,超出部分裁剪(cover模式:尽量铺满屏幕) float videoAspect = player.width / (float)Mathf.Max(1, (int)player.height); var fullRt = currentFullImage.rectTransform; var fullParent = fullRt.parent as RectTransform; @@ -177,41 +205,36 @@ namespace Kill.UI.Components { float parentW = fullParent.rect.width; float parentH = fullParent.rect.height; - // 检测全屏UI是否旋转了90°(横屏视频旋转90°后铺满竖屏手机屏幕) + // 检测全屏UI是否旋转了90° float rotZ = Mathf.Abs(Mathf.DeltaAngle(fullRt.localEulerAngles.z, 0f)); bool rotated90 = rotZ >= 45f && rotZ <= 135f; - if (rotated90) + + // 视觉屏幕 = 父 stretch 覆盖区域,即手机屏幕真实宽高(与UI旋转无关) + float screenVisualW = parentW; + float screenVisualH = parentH; + // 按视频/屏幕比例决定贴齐哪一边,确保视频占屏幕比例最大化 + float visualW, visualH; + if ((1f / videoAspect) > (screenVisualW / screenVisualH)) { - // 旋转90°的UI:矩形宽高互换,旋转后视觉铺满屏幕 - fullRt.anchorMin = new Vector2(0.5f, 0.5f); - fullRt.anchorMax = new Vector2(0.5f, 0.5f); - fullRt.pivot = new Vector2(0.5f, 0.5f); - fullRt.sizeDelta = new Vector2(parentH, parentW); + // 视频长边贴屏幕短边(横向贴满,留黑上下) + visualW = screenVisualW; + visualH = visualW * videoAspect; } else { - fullRt.anchorMin = Vector2.zero; - fullRt.anchorMax = Vector2.one; - fullRt.pivot = new Vector2(0.5f, 0.5f); - fullRt.sizeDelta = Vector2.zero; - } - // 按视频比例裁剪(cover):旋转后视频宽对应屏幕高,显示比例需取反 - float frameAspect = rotated90 ? parentH / parentW : parentW / parentH; - if (Mathf.Abs(frameAspect - videoAspect) >= 0.001f) - { - if (videoAspect > frameAspect) - { - // 视频相对更宽:裁剪左右 - float uvW = frameAspect / videoAspect; - currentFullImage.uvRect = new Rect((1 - uvW) / 2f, 0, uvW, 1); - } - else - { - // 视频相对更窄:裁剪上下 - float uvH = videoAspect / frameAspect; - currentFullImage.uvRect = new Rect(0, (1 - uvH) / 2f, 1, uvH); - } + // 视频长边贴屏幕长边(纵向贴满,留黑左右) + visualH = screenVisualH; + visualW = visualH / videoAspect; } + // RectTransform 的 sizeDelta:UI 旋转 90° 时 (x,y) = (visualH, visualW) + float rtW = rotated90 ? visualH : visualW; + float rtH = rotated90 ? visualW : visualH; + + fullRt.anchorMin = new Vector2(0.5f, 0.5f); + fullRt.anchorMax = new Vector2(0.5f, 0.5f); + fullRt.pivot = new Vector2(0.5f, 0.5f); + fullRt.sizeDelta = new Vector2(rtW, rtH); + fullRt.anchoredPosition = Vector2.zero; } } videoPlayer.frame = 0;