SwiftUI 视图首选项:overlayPreferenceValue 在复杂容器上使用时返回 nil

Posted

技术标签:

【中文标题】SwiftUI 视图首选项:overlayPreferenceValue 在复杂容器上使用时返回 nil【英文标题】:SwiftUI view preferences: overlayPreferenceValue returns nil when used on complex containers 【发布时间】:2020-05-26 07:54:20 【问题描述】:

我正在尝试使用anchorPreference 在我的 VStack 中的某些视图上绘制叠加层。 但是,它只适用于最简单的情况。当我的 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
                )
            
        
    
  
 

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

【问题讨论】:

【参考方案1】:

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

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

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

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 !!
        
    
  
 

【讨论】:

以上是关于SwiftUI 视图首选项:overlayPreferenceValue 在复杂容器上使用时返回 nil的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 选项卡视图显示表

滑动选项 swiftUI 滚动视图

更改选项卡式视图 SwiftUI 的凹槽区域背景颜色

SwiftUI:输入字段键盘动画导致选项卡视图中的其他视图动画

SwiftUI 自动调整底页大小

处理选项卡选择 SwiftUI