Как бы вы создали массив представлений для циклического просмотра, чтобы создать навигационную ссылку для каждого из представлений?

avatar
William Wang
1 июля 2021 в 19:11
140
1
1

У меня есть 8 представлений, где в группе горизонтальной прокрутки пользователь нажимает на изображение и переходит к соответствующему представлению. Я знаю, что мог бы сделать это вручную, но использование цикла ForEach сэкономит много кода. Требования к навигационной ссылке затрудняют обращение к самому представлению , как это было бы, т.е. [собаки_и_кошки, но навигационная ссылка хочет, чтобы это были собаки_и_кошки()]. Тем не менее, это не работает из-за ошибок: тип «Any» не имеет члена «init» в строке ссылки навигации и не может преобразовать значение типа «Barcelona_Museum_of_Contemporary_Art.Type» в ожидаемый тип элемента «Any.Protocol» для каждого из элементы массива. Если бы вы были на моем месте, как бы вы создали массив объектов представления, если это возможно, и перебирали бы их для каждой навигационной ссылки?


let museumNamesForLink = [Whitney_Museum_of_American_Art, 
The_Andy_Warhol_Museum, 
Museum_of_Modern_Art, Nakamura_Keith_Haring_Collection, 
Tate_Modern, 
The_Broad_Museum, 
Museum_fu_r_Moderne_Kunst, 
Barcelona_Museum_of_Contemporary_Art]

                     
                    ScrollView(.horizontal, showsIndicators: false) {
                        
                        HStack(alignment: .top, spacing: 0) {
                            
                            ForEach(museumNames.indices) { index in
                                
                                VStack {
                                    NavigationLink(destination: museumNamesForLink[index]()) {
                                            Image(museumNames[index])
                                                .resizable()
                                                .aspectRatio(contentMode: .fit)
                                        
                                    }
                                    Text(museumNames[index])
                                         .bold()
                                         .font(.callout)
                                         .foregroundColor(.white)
                                         .multilineTextAlignment(.center)
                                         .padding(.leading)
                                }
                            }
                        }
                    }
Источник

Ответы (1)

avatar
jnpdx
1 июля 2021 в 19:29
1

Я бы, вероятно, подошёл к этому с помощью enum для представления различных типов музеев, а затем функции @ViewBuilder с оператором switch, который может дать вам другой View на основе которого enum к нему.

struct ContentView: View {
    
    enum MuseumTypes: CaseIterable {
        case whitney, warhol, moma
        
        var name : String {
            switch self {
            case .whitney:
                return "Whitney Museum"
            case .warhol:
                return "Warhol Musuem"
            case .moma:
                return "Museum of Modern Art"
            }
        }
    }
    
    @ViewBuilder func museumViewForType(type: MuseumTypes) -> some View {
        switch type {
        case .whitney:
            WhitneyView()
        case .warhol:
            WarholView()
        case .moma:
            MomaView()
        }
    }
    
    var body: some View {
        NavigationView {
            VStack {
                ForEach(MuseumTypes.allCases, id: \.self) { museum in
                    NavigationLink(destination: museumViewForType(type: museum)) {
                        Text(museum.name)
                    }
                }
            }
        }
    }
}

struct WhitneyView : View {
    var body: some View {
        Text("Whitney")
    }
}

struct WarholView : View {
    var body: some View {
        Text("Warhol")
    }
}

struct MomaView : View {
    var body: some View {
        Text("MOMA")
    }
}

Альтернативный подход состоит в том, чтобы хранить все ваши представления в массиве и заключать их в AnyView(), чтобы они были однородными типами (см. https://coderhelper.com/a/66057289/560942), но я думаю это не так чисто и ясно, как описанный выше подход). Кроме того, используя enum вместо массива, вы получите предупреждения от компилятора, если забудете регистр, и это гарантирует, что вы ничего не пропустите и не выйдете за пределы индексов вашего массива.