SwiftUI在GeometryReader中关闭Sheet动画过程的常见坑
SwiftUI在GeometryReader中关闭Sheet动画过程的常见坑

SwiftUI在GeometryReader中关闭Sheet动画过程的常见坑

在SwiftUI中,为了让我的视图宽度适配多种设置,我从GeometryReader中获取屏幕的宽度,并设置到对应的VStack中。

GeometryReader { geo in
    let width = geo.frame(in: .global).width * 0.95
    let height = geo.frame(in: .global).height
    VStack {
        // 省略内容
    }
        .frame(width: width,height:110)
}

从Gif动画中可以看到,主视图顶部的黑色区域在Sheet关闭时,黑色区域的宽度会直接放大,缺失了动画缩放的效果。当然Gif动画因为本身的帧数限制,可能看的并不是很清楚。

这一问题的原因主要在于当Sheet关闭后,VStack的width就需要根据 frame(in: .global) 计算出的宽度变宽,这这也就会导致在动画过程中,VStack的宽度瞬间变大。

解决方案:使用 .frame(in: .local) 或者更安全的 UIScreen.main.bounds.width:

GeometryReader { geo in
    let width = geo.frame(in: .local).width * 0.95  // 改为 .local
    let height = geo.frame(in: .local).height
    VStack {
        // 省略内容
    }
        .frame(width: width,height:110)
}

使用 .frame(in: .local)后,问题得到解决。

扩展知识

.frame(in: .local) 和 .frame(in: .global)的区别

GeometryProxy.frame(in:) 是 SwiftUI 中一个方法,用来获取当前视图在某个坐标空间(CoordinateSpace)中的位置和大小,返回的是一个 CGRect。

.local:当前视图坐标系自身,自身左上角是 (0,0),宽高是自己大小。

.global,整个屏幕,用于测量一个视图在屏幕上的绝对位置。

为什么 .global 会导致 sheet 关闭时宽度突变?

1、.global

当视图处于动画状态(例如正在从 .sheet 消失),SwiftUI 会把它从原布局结构中移出,暂时放在一个系统管理的动画容器里。

这时候 .global 坐标系就无法正确反映原来看到的视图大小,它可能会返回整个屏幕的宽度,甚至一个奇怪的大值。

所以当拿 .global.width 来设置 .frame(width:),就等于“用错了参考线”。

2、.local

.local 总是从视图自己的坐标系来出发,左上角是 (0,0),大小是视图当前真实的布局大小。

即使在动画中,只要 GeometryReader 本身还在,它的 .local 尺寸是稳定的。

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注