【问题标题】:Conditional rendering with optionals in SwiftUI在 SwiftUI 中使用选项进行条件渲染
【发布时间】:2019-10-29 13:01:04
【问题描述】:

来自 React 背景很容易只在定义了值的情况下渲染视图。它看起来像这样:

function Component ({ profile }) {
  return (
    <div>{profile && <div>{profile.name}}</div>
  )
}

但我发现在 SwiftUI 中复制这种模式要困难得多。理想情况下,我们可以在视图中使用条件展开,但这目前不起作用。我能想出的唯一解决方案真的很不优雅:

struct ProfileView : View {
    var profile: Profile?

    var body : some View {
        if let profile = profile {
            return Text("profile: \(profile.bio)")
        }  else {
            return Text("")
        }
    }
}

struct LayoutView : View {
    @State var profile: Profile?
    var body : some View {
        Group {
            ProfileView(profile: profile)
        }
    }.onAppear(perform: fetch)

    // fetch method 
}

有没有人有一些更好的使用可选值进行条件渲染的策略?

【问题讨论】:

  • Text(profile != nil ? "profile: \(profile!.bio)" : "") 替换整个if let 块。这里没有特定于 SwiftUI 的内容。
  • 天啊,我从来没有考虑过使用 !操作员。说到 Swift,我完全是个新手……显然,嘿。

标签: swift swiftui


【解决方案1】:

您可以反过来使用map 来处理可选项,如下所示:

struct ProfileView : View {
    var profile: Profile?

    var body : some View {
        profile.map { Text("profile: \($0.bio)") }
    }
}

(在此示例中,$0 是您未包装的 profile。)

如果需要 else 情况:

profile.map { Text($0.bio) } ?? Text("Not available")

【讨论】:

    【解决方案2】:

    这样做:

    struct LayoutView : View {
        @State var profile: Profile?
        var body : some View {
            Group {
                if profile != nil {
                    ProfileView(profile: profile!)
                }
            }
        }.onAppear(perform: fetch)
    
        // fetch method 
    }
    

    【讨论】:

    • 似乎与原始问题没有密切关系。
    【解决方案3】:

    我会在子视图ProfileView 中使用@Binding,以确保文本在更改时与profile 数据同步。这就是我要做的一切:

    struct Profile {
        var bio: String = "Biography"
    }
    
    struct ProfileView : View {
        @Binding var profile: Profile?
        private var profileText: String {
            get {
                profile == nil ? "" : "profile: " + profile!.bio
            } // set part is not necessary if we don't set the text from the view
            set {
                self.profile?.bio = newValue
            }
        }
    
        var body : some View {
            Text(profileText)
        }
    }
    
    struct LayoutView : View {
        @State var profile: Profile?
        var body : some View {
            Group {
                ProfileView(profile: $profile)
            }
        }
    }
    
    // check it via preview
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            LayoutView(profile: Profile())
        }
    }
    

    【讨论】:

    • 为什么需要这么多行代码?难道没有更优雅的方法吗?
    • 是的,有一些方法可以缩短回答时间,但解决方案与问题相匹配,并且很容易上手。更优雅的方法是立即声明 @Bindable var 并在创建时将 get-set 逻辑移入其中。 developer.apple.com/documentation/swiftui/binding/3363053-init
    猜你喜欢
    • 2018-05-08
    • 1970-01-01
    • 2020-08-21
    • 2020-01-15
    • 1970-01-01
    • 2020-09-20
    • 2021-11-13
    • 2017-08-20
    • 2020-10-19
    相关资源
    最近更新 更多