ios - SwiftUI View 首选项 : overlayPreferenceValue returns nil when used on complex containers

标签 ios swift swiftui

我正在尝试使用 anchorPreference在我的 VStack 中的某个 View 上绘制叠加层。
但是,它仅适用于最简单的情况。当我的 VStack 的内容变得有点复杂时,从不绘制叠加层。

这是我的代码

struct debug_test: View {
@State private var someState = false

var body: some View {
    VStack {
        Text("Hello World !!!")
            .anchorPreference(
                key: BoundsPreferenceKey.self,
                value: .bounds
            ) { $0 }

        //////////////////////////////////////////////////////////
        // When I remove below lines - it works ok.
        // But when I put add some conditionally-visible view and one more view
        // it stops drawing an overlay.
        // Apparently, `preferences` is always nil in that case.
        if someState {
            Text("Pooop")
        }
        Text("Pooop2")
        //////////////////////////////////////////////////////////
    }
    .overlayPreferenceValue(BoundsPreferenceKey.self) { preferences in
        GeometryReader { geometry in
            preferences.map {
                Rectangle()
                    .stroke(Color.red, lineWidth: 5)
                    .frame(
                        width: geometry[$0].width,
                        height: geometry[$0].height
                )
                    .offset(
                        x: geometry[$0].minX,
                        y: geometry[$0].minY
                )
            }
        }
    }
  }
 }

正如我在代码注释中所解释的那样,当我得到一个内部只有一个 View 的简单堆栈时,它工作正常。但是当我在里面添加更多 View 和一些条件时,它停止工作。
任何线索如何解决它?

最佳答案

首选项在布局期间更新,我假设您的首选项键保持不变 Anchor<CGRect>?在布局结束时重置为零。

这是固定变体。使用 Xcode 11.4/iOS 13.4 测试。

注意:我建议为您的自定义首选项键使用显式结构模型。考虑 this solution for example

demo

struct BoundsPreferenceKey: PreferenceKey {
    static var defaultValue: [Anchor<CGRect>] = [] // << use something persistent

    static func reduce(value: inout [Anchor<CGRect>], nextValue: () -> [Anchor<CGRect>]) {
        value.append(contentsOf:nextValue())
    }
}

struct debug_test: View {
@State private var someState = false

var body: some View {
    VStack {
        Text("Hello World !!!")
            .anchorPreference(
                key: BoundsPreferenceKey.self,
                value: .bounds
            ) { [$0] }

        if someState {
            Text("Pooop")
        }
        Text("Pooop2")
        //////////////////////////////////////////////////////////
    }
    .overlayPreferenceValue(BoundsPreferenceKey.self) { preferences in
        GeometryReader { geometry in
            preferences.map {
                Rectangle()
                    .stroke(Color.red, lineWidth: 5)
                    .frame(
                        width: geometry[$0].width,
                        height: geometry[$0].height
                )
                    .position(    // << here is fix as well !!
                        x: geometry[$0].midX,
                        y: geometry[$0].midY
                )
            }[0]     // << just for demo, this should be more safe !!
        }
    }
  }
 }

关于ios - SwiftUI View 首选项 : overlayPreferenceValue returns nil when used on complex containers,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62017158/

相关文章:

ios - 以编程方式创建与点击按钮关联的标签

ios - MBProgressHUD 禁用与 UITableViewController 的交互

ios - 从 iOS 应用程序将视频上​​传到 youtube 返回 400

SwiftUI - 从列表中删除项目崩溃并出现 fatal error : Index out of range

ios - Swift iOS Playground : Error sending deferral props

ios - 如何根据键对数组进行排序?

swift - MPSNNGraph reshape 节点

arrays - 在 Swift 中使用委托(delegate)数组时如何避免保留循环

ios - SwiftUI 模态演示仅在 navigationBarItems 中有效

ios - SwiftUI - 反转 bool 绑定(bind)