SwiftUi - 填充宽屏

SwiftUi - Filling a wide-aspect screen

TL;DR:

我无法在宽屏 (13:6) phone 上准确地将图像绘制到全屏上。如果我观察安全区域,错误是(可以预见的)欠扫描。使用 .edgesIgnoringSafeArea() 在另一个方向上(出乎意料地)走得太远了。

更新

Apple DTS 已建议这是一个错误,向我退还了一次支持事件,并邀请我提交错误报告。它在 https://feedbackassistant.apple.com/feedback/8192204

的管道中

告诫讲师

我对 .scaledToFill 的推测可能是错误的。我在最后解决这个问题。

代码

太基础了,我可以把它放在这里,它甚至不会减慢你的速度

struct ContentView: View {
    var body: some View {
        Image("testImage").resizable().scaledToFill()
//        .edgesIgnoringSafeArea(.all)
    }
}

测试图片

测试图像是横向矩形,比例为 13:6,与宽 phone 相同。 (例如812:375原始iPhone X的比例。)灰色外围不是图像的一部分。

它的子帧已标记,对应于窄(旧)phones (16:9) 和垫 (4:3)。

运行时结果

对于 pad 和 phones,Xcode 项目设置明确仅限横向。

对于窄 phones 和所有 pad,上面的代码,观察安全区域,像我期望的那样渲染测试图像:

但是在宽 phones 上,我无法让红色矩形与屏幕边缘重合。

宽屏手机

没有调用.edgesIgnoringSafeArea(),即我们正在观察安全区域。自然地,我们的图像被映射到全屏的一个子集。

调用.edgesIgnoringSafeArea()。我希望它能完全填满屏幕,但它会过扫描:

这是 Xcode 视图层次调试器对上一个的看法:图像被映射到比全屏 的矩形。为什么?

事件顺序

如果我颠倒修饰符的顺序,并在.scaledToFill()之前调用.edgesIgnoringSafeArea(),我会得到宽高比失真,.scaledToFill()是应该防止。 (请参阅屏幕截图中的圆圈变成椭圆形。)解释这些操作的组成方式以及它们为什么不通勤,可能对回答我的主要问题有很大帮助。

解决方法

我认为以上应该可行,但我不明白为什么不行。 在宽 phone 上的作用是消除 .scaledToFill 修饰符。然后你明白了。但它之所以有效,是因为测试图像 已经 与显示器的确切宽高比——不是一个非常通用的解决方案。

缩放填充

在风景图像和显示的受限域中,我希望 13:6 测试图像上的缩放填充操作等同于(具有以下语义):

  1. 在目标(容器)矩形中居中测试图像,大小完全适合容器。
  • 我一直以为忽略安全区域意味着“目的地”将是全屏,但这可能是我犯错的地方。
  1. 扩大测试图像,保持比例和中心,直到一对边与容器的边重合。
  • 对于较窄的显示,左右边缘将首先相遇,顶部和底部将在目标矩形内。
  1. 但不要现在停下来。那将是适合的比例,或信箱。
  2. 展开直到顶部和底部与容器的顶部和底部重合。
  • 对于较窄的显示器,这意味着两侧的内容都会被裁剪
  • 对于13:6显示,所有四个图像边缘将同时与显示边缘重合。

我不知道为什么 .edgesIgnoringSafeArea() 不能正常工作,但这里有一个解决方法应该可以帮助您。

    GeometryReader { geo in
       Image("testImage")
          .resizable()
          .scaledToFill()
          .frame(width: geo.size.width, height: geo.size.height)
    }
    .edgesIgnoringSafeArea(.all)

更新: 这是不用 GeometryReader 做同样事情的另一种方法:

Image("testImage")
    .resizable()
    .scaledToFill()
    .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
    .edgesIgnoringSafeArea(.all)