在 ForEach 视图中使用 Conditional 对每个视图应用不同的效果

Posted

技术标签:

【中文标题】在 ForEach 视图中使用 Conditional 对每个视图应用不同的效果【英文标题】:Using Conditional Inside a ForEach view to apply different effects to each view 【发布时间】:2020-05-18 20:39:51 【问题描述】:

我正在尝试呈现数组中的项目列表。数组项是具有字符串和整数的结构。我希望数组中整数大于 0 的项目左对齐,等于 0 居中对齐,小于 0 右对齐。将来我希望能够应用其他一些差异,但现在我只需要不同的对齐方式。

我曾尝试使用 ForEach 视图循环遍历数组中的项目,并使用 if else 语句尝试两种不同的显示方式,但我收到一个错误,即 () 无法适应“查看”。

编辑:添加确切的错误消息:Type '()' cannot conform to 'View'; only struct/enum/class types can conform to protocols

这是我在 ForEach 中循环的结构:

struct PreviouslyPlayedData: Hashable 
        let text: String
        let speaker: Int
    

这是我现在设置的 ForEach,它给出了错误。

ForEach(previouslyPlayed, id: \.self)  data in
                if (data.speaker == 0) 
                    Text(data.text)
                    .frame(width: 300, height: nil, alignment: .center)
                 else 
                    Text(data.text)
                        .frame(width: 300, height: nil, alignment: .leading)
                

            

【问题讨论】:

它给出了什么错误? 类型 '()' 不能符合 'View';只有结构/枚举/类类型可以符合协议 【参考方案1】:

您不能在ForEach 中使用条件。

SwiftUI 在幕后做了很多工作,它只是希望您的 ContentView 中只包含一种非常特定类型的 View。它不关心哪种类型的视图(因此是-> some View),但它确实关心只能返回一种类型。虽然有时你可以保证在你的条件句中,Swift 不能为你完全理解它。

您有多种解决方法。如果你的逻辑比较简单,不需要修改太多,可以使用三元运算符来切换样式:

ForEach(previouslyPlayed, id: \.self)  data in
    Text(data.text)
    .frame(width: 300, height: nil, alignment: data.speaker == 0 ? .center : .leading)

【讨论】:

【参考方案2】:

另一种方法是在自己的视图中显示每个项目,它可以根据项目处理对齐,并使用主内容视图显示列表:

例如:

import SwiftUI

struct PreviouslyPlayedData: Identifiable 
    let id = UUID() // To make it easier to use in lists
    let text: String
    let speaker: Int

    static var previewItems: [PreviouslyPlayedData] 
        [PreviouslyPlayedData(text: "First", speaker: -1),
         PreviouslyPlayedData(text: "Second", speaker: -1),
         PreviouslyPlayedData(text: "third", speaker: 0),
         PreviouslyPlayedData(text: "Fourth", speaker: 1),
         PreviouslyPlayedData(text: "Fifth", speaker: -1),
         PreviouslyPlayedData(text: "Sixth", speaker: 2),
        ]
    


struct ContentView: View 
    var items = PreviouslyPlayedData.previewItems

    var body: some View 
        List(items)  item in
            DataView(item: item)
        
    


struct DataView: View 
    let item: PreviouslyPlayedData

    var itemAlignment: Alignment 
        if item.speaker < 0 
            return .leading
         else if item.speaker == 0 
            return .center
         else 
            return .trailing
        
    


    var body: some View 
        Text(item.text).frame(maxWidth: .infinity, alignment: itemAlignment)
    


struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        ContentView()
    

看起来像:

【讨论】:

以上是关于在 ForEach 视图中使用 Conditional 对每个视图应用不同的效果的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SwiftUI 中使用 Foreach 视图?

如何在视图页面中使用 foreach

在视图中使用 foreach 的 Codeigniter

在 ForEach 视图中使用 Conditional 对每个视图应用不同的效果

在 Laravel 视图中使用 foreach 变量

SwiftUI - 使用 ForEach 时,您应该在子视图中使用 `@State var` 还是 `let`