SwiftUi-填充宽屏屏幕

时间:2020-06-03 03:50:12

标签: layout swiftui aspect-ratio safearealayoutguide

TL; DR

在宽屏(13:6)手机上,我无法在全屏上准确绘制图像。如果我观察到安全区域,则错误(可预测)是欠扫描。使用.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的比例缩放。 (例如原始iPhone X的812:375比例。)灰色外围不是图像的一部分。

test image

其子帧带有标记,分别对应于较窄(较旧)的手机(16:9)和平板电脑(4:3)。

运行时结果

对于平板电脑和手机,Xcode项目设置均明确为仅横向使用。

对于狭窄的手机和所有键盘,上面的代码(观察安全区域)会像我期望的那样呈现测试图像:

first results

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

宽手机

通过 no 呼叫.edgesIgnoringSafeArea(),这就是我们正在观察安全区域。自然,我们的图像会映射到全屏的一个子集。

wide phone

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

enter image description here

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

enter image description here

事件顺序

如果我颠倒修饰符的顺序,并在{em> .edgesIgnoringSafeArea()之前调用.scaledToFill() ,则会出现宽高比失真,.scaledToFill()应该可以防止这种情况。 (请参见在屏幕快照中圆圈变成椭圆形。)对这些操作的组成方式以及为什么不进行上下班的解释可能对回答我的主要问题大有帮助。

ipad 11 distortion

解决方法

我认为上面的方法应该起作用,但我不明白为什么不这样。在宽手机上,起作用的作用是消除.scaledToFill修饰符。然后你得到这个。但这只是有效,因为测试图像已经已经与显示器完全一样的长宽比了–并不是很通用的解决方案。

enter image description here

缩放以填充

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

  1. 将测试图像在目标(容器)矩形中居中,其大小应完全适合容器中的尺寸。
  • 我一直希望忽略安全区域意味着“目的地”将是全屏显示,但这可能是我犯错的地方。
  1. 展开测试图像,保持比例和中心,直到一对侧面与容器的侧面重合。
  • 对于较窄的显示,左边缘和右边缘将首先相遇,并且顶部和底部将在目标矩形内。
  1. 但不要立即停止。那将是可缩放以适合的大小,也就是信箱。
  2. 展开,直到顶部和底部与容器顶部和底部重合。
  • 对于较窄的显示屏,这意味着将在两侧均裁切内容
  • 对于13:6的显示,所有四个图像边缘将同时与显示边缘重合。

1 个答案:

答案 0 :(得分:2)

我不知道为什么.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)