SwiftUI ForEach 循环多个数组

时间:2021-02-20 00:54:15

标签: json swiftui

我很难弄清楚如何在 SwiftUI 中 ForEach 循环一些 arrayarray json 数据。我使用 https://app.quicktype.io 从这个 URL here 获取我的数据结构。

我希望获得类 FeaturedHeaderViewFeaturedPackageView,它们的标题为“Hot Right Now”和“What We're Using”,其中还包含 FeaturedPackageView 数据。我的问题是我只重复循环第一个 FeaturedHeaderViewFeaturedPackageView,我假设每个部分有两个。我的 data struct 不正确吗?我从未尝试过复杂的 json 数据,所以我不确定如何正确处理它,以及 ForEach 循环是否是我正在寻找的。最终目标是让 List 带有“现在很热”和它的项目,然后是“我们正在使用的东西”和它的项目。

我能够使用两个 FeaturedBannersView 循环很好地获得 ForEach 类,并认为这对其余数据是相同的方法?

Banner View

横幅视图工作

ScrollView(.horizontal) {
    HStack {
        ForEach(self.welcome.views,  id: \.viewClass) { views in
            ForEach(views.banners ?? [], id:\.url) { banner in
                ZStack (alignment: .bottomLeading) {
                    GeometryReader { geometry in
                        RequestImage(Url(banner.url), animation: nil)
                            .aspectRatio(contentMode: .fit)
                            .frame(width: geometry.size.width)
                            .clipped()
                            .cornerRadius(CGFloat(views.itemCornerRadius ?? 0))
                    }
                    HStack {
                        Text(banner.title ?? "")
                            .fontWeight(.bold)
                            .font(.title3)
                            .foregroundColor(Color.white)
                    }
                    .padding(.all, 15)
                }
                .frame(width: 263, height: 148)
            }
        }
    }
    .padding(.leading, 10)
    .padding(.trailing, 10)
}

问题

Issue

我的数据结构

struct Welcome: Codable {
    let views: [WelcomeView]
}

struct WelcomeView: Codable {
    let viewClass: String?
    let banners: [Banner]?
    let views: [PurpleView]?

    enum CodingKeys: String, CodingKey {
        case viewClass = "class"
        case views
    }
}

struct Banner: Codable {
    let url: String?
    let title, package, repoName: String?
}

struct PurpleView: Codable {
    let viewClass: String?
    let views: [FluffyView]

    enum CodingKeys: String, CodingKey {
        case viewClass = "class"
        case views
    }
}

struct FluffyView: Codable {
    let viewClass: String?
    let title: String?
    let package, packageName, packageAuthor: String?
    let repoName: RepoName?
    let packageIcon: String?

    enum CodingKeys: String, CodingKey {
        case viewClass = "class"
        case title, package, packageName, packageAuthor, repoName, packageIcon
    }
}

enum RepoName: String, Codable {
    case chariz = "Chariz"
    case packix = "Packix"
}

List {
    ForEach(self.welcome.views, id: \.viewClass) { view in
        ForEach(view.views ?? [], id: \.viewClass) { purple in
            ForEach(purple.views, id: \.packageName) { fluffy in
                if fluffy.viewClass == "FeaturedHeaderView" {
                    Text(fluffy.title ?? "")
                        .font(.title3)
                        .fontWeight(.bold)
                } else {
                    HStack (spacing: 15){
                        RequestImage(Url(fluffy.packageIcon ?? ""), animation: nil)
                            .aspectRatio(contentMode: .fit)
                            .frame(width: 60, height: 60)
                            .clipped()
                            .cornerRadius(13.5)
                        VStack (alignment: .leading){
                            Text(fluffy.packageName ?? "")
                                .font(.body)
                            Text(fluffy.packageAuthor ?? "")
                                .foregroundColor(Color.secondary)
                                .font(.callout)
                            Text(fluffy.repoName?.rawValue ?? "")
                                .foregroundColor(Color.secondary)
                                .font(.subheadline)
                        }
                    }
                }
            }
        }
    }
}
.onAppear() {
    request()
}

1 个答案:

答案 0 :(得分:1)

您得到重复的原因是您使用 .viewClass.packageName 作为 ForEach 循环的 ID,但在 JSON 中,这些值是 <强>不是实际上是独一无二的。例如,FeaturedStackView 会重复。

如何解决:

将 ID 添加到您的模型并将其用于 ForEach 键。


// MARK: - WelcomeView
struct WelcomeView: Codable {
    var id = UUID() //<-- HERE
    let viewClass: String
    let itemSize: String?
    let itemCornerRadius: Int?
    let banners: [Banner]?
    let horizontalSpacing: Int?
    let views: [PurpleView]?

    enum CodingKeys: String, CodingKey {
        case viewClass = "class"
        case itemSize, itemCornerRadius, banners, horizontalSpacing, views
    }
}

struct PurpleView: Codable {
    var id = UUID()
    let viewClass: String
    let preferredWidth: Int
    let views: [FluffyView]
    let xPadding: Int?

    enum CodingKeys: String, CodingKey {
        case viewClass = "class"
        case preferredWidth, views, xPadding
    }
}

struct FluffyView: Codable {
    var id = UUID()
    let viewClass: String
    let title: String?
    let useBoldText: Bool?
    let package, packageName, packageAuthor: String?
    let repoName: RepoName?
    let packageIcon: String?
    let orientation: String?
    let views: [TentacledView]?
    let text: String?
    let action: String?
    let yPadding: Int?

    enum CodingKeys: String, CodingKey {
        case viewClass = "class"
        case title, useBoldText, package, packageName, packageAuthor, repoName, packageIcon, orientation, views, text, action, yPadding
    }
}

然后,在每个 ForEach 循环中,使用 id: \.id