【问题标题】:SwiftUI Pass Value from Geometry Reader to FunctionSwiftUI 将值从几何阅读器传递给函数
【发布时间】:2020-03-03 20:19:57
【问题描述】:

我有一个视图,它使用 Geometry Reader 来计算图像区域的大小:

GeometryReader { metrics in
    ZStack{
        self.image
           .resizable()
           .frame(width:  (metrics.size.height - 10) * 0.561403509 , height: metrics.size.height - 10, alignment: .top)
           .clipped()
    }
}

但我有一个函数,我想使用 GeometryReader 计算的帧高度和宽度来裁剪图像。

我有一个单独的函数,可以在按下按钮时裁剪图像:

 DownloadImageButton(prepareImagefunction: { self.prepareImage() })

然后调用 prepareImage 函数:

func prepareImage( ) {
 // In order for image cropping to work, we need the equivalent of view.bounds in order to adjust the crop so that it correctly measures the crop area. We need metrics.width and metrics.height 
 var adjustmentScaleForDisplaySize = targetSize.width / metrics.width

请注意,GeometryReader 是调用 prepareImage 的父视图的子视图。因此,理想情况下,子节点会将指标值保存在 EnvironmentObject 或绑定到父节点中。

【问题讨论】:

  • 您能否添加一个示例来说明您要完成的工作,即使它不起作用? metric 可以像任何其他变量一样传递给函数,但不清楚您要做什么。
  • 感谢您的评论。我已经编辑了答案。当图像显示在屏幕上时,我需要保存 metrics.size 以便稍后在父视图的图像裁剪功能中使用它。如果您考虑图像裁剪,通常您使用 view.bounds 来确定裁剪区域。这是等效的要求。

标签: swift swiftui


【解决方案1】:

有没有办法将 GeometryReader 计算的值传递给函数?

是的,您可以这样做。 var metricsGeometryProxy,所以函数签名应该如下例所示

private func resizedImage(for metrics: GeometryProxy) -> some View {
    self.image
       .resizable()
       .frame(width:  (metrics.size.height - 10) * 0.561403509 , height: metrics.size.height - 10, alignment: .top)
       .clipped()
}

所以你的用法

GeometryReader { metrics in
    ZStack{
       self.resizedImage(for: metrics)
    }
}

更新:更改请求

假设您在子视图中绑定为

@Binding var cropSize: CGSize

上面的函数可以修改如下

private func resizedImage(for metrics: GeometryProxy) -> some View {
    let size = CGSize(width: (metrics.size.height - 10) * 0.561403509, 
                           height: metrics.size.height - 10)
    self.cropSize = size
    return self.image
       .resizable()
       .frame(width: size.width, height: size.height, alignment: .top)
       .clipped()
}

【讨论】:

  • 这真的很棒。但我想做的是将度量值传递给图像裁剪函数。因此,我需要捕获度量高度,例如,以便将其用于裁剪功能。我会附加我的问题,但你的答案肯定接近我的要求!
  • 我现在已经测试过了,self.cropSize = size 会抛出一个错误:[SwiftUI] Modifying state during view update,这会导致未定义的行为。裁剪大小不会传递给父级。
  • @dot3,它取决于cropSizebody 构造的使用顺序(未显示),无论如何这不是危急情况,通常已知的解决方案是使其异步,喜欢:DispatchQueue.main.async { self.cropSize = size }
【解决方案2】:

由于我实际上只需要裁剪大小,并且不一定需要返回图像,因此我执行了以下操作,这也有助于避免在接受的答案中出现错误:

[SwiftUI] Modifying state during view update, this will cause undefined behavior.

我添加了一个 .onAppear 函数调用,有助于避免上述错误,然后将裁剪尺寸正确传递给父级:

GeometryReader { metrics in
  ZStack{
   self.image
   .resizable()
   .frame(width:  (metrics.size.height - 10) * 0.561403509 , height: metrics.size.height - 10, alignment: .top)
   .clipped()
  }.onAppear{
    self.saveCropSize(for: metrics)
  }....

private func saveCropSize(for metrics: GeometryProxy){
    let size = CGSize(width: (metrics.size.height - 10) * 0.561403509, 
                           height: metrics.size.height - 10)
    self.cropSize = size
}

【讨论】:

    【解决方案3】:

    我提出了一个我认为有用的解决方案,使用了一种新类型:

    public struct GeometryPasser: View {
        private let op: (GeometryProxy) -> Void
        public init(_ op: @escaping (GeometryProxy) -> Void) {
            self.op = op
        }
        
        public var body: some View {
            GeometryReader { proxy in
                Color.clear.onAppear {
                    op(proxy)
                }
            }
        }
    }
    
    extension View {
        public func passGeometry(_ op: @escaping (GeometryProxy) -> Void) -> some View {
            self.background(
                GeometryPasser(op)
            )
        }
    }
    

    然后像这样调用:

    Rectangle()
        .fill(.yellow)
        .passGeometry { geo in
            print("do whatever you want here: \(geo)")
        }
    

    【讨论】:

      猜你喜欢
      • 2019-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-25
      • 2012-07-15
      相关资源
      最近更新 更多