SwiftUI 将值从几何阅读器传递给函数

Posted

技术标签:

【中文标题】SwiftUI 将值从几何阅读器传递给函数【英文标题】:SwiftUI Pass Value from Geometry Reader to Function 【发布时间】: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 来确定裁剪区域。这是等效的要求。 【参考方案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)")
    

【讨论】:

以上是关于SwiftUI 将值从几何阅读器传递给函数的主要内容,如果未能解决你的问题,请参考以下文章

如何将值从 javascript 函数传递到 django 视图

如何将值从 v-select 传递给方法 - 它始终与默认值相同

将值从 Azure 逻辑应用程序传递到 HttpTrigger Azure 函数

如何将值从 javascript 传递到 iOS UIWebView

在 Angular 中,当组件不是父/子时,如何将值从一个组件传递到另一个组件?

如何将值从angularjs传递给节点[重复]