簡體   English   中英

SwiftUI 中不同視圖的數組可在列表中作為 NavigationLink 進行迭代

[英]Array of different Views in SwiftUI iterable in a list as NavigationLink

我正在制作一個具有各種屏幕的應用程序,我想在一組視圖中收集所有符合View的屏幕。 在應用程序的主屏幕上,我想向所有屏幕標題顯示帶有NavigationLink的列表。 我遇到的問題是,如果我嘗試創建一個自定義視圖結構並擁有一個初始化給給定屏幕並返回它的屬性。 我一直遇到問題,編譯器迫使我更改變量以接受any View而不僅僅是View或刪除的類型some View

struct Screen: View, Identifiable {
    var id: String {
        return title
    }
    
    let title: String
    let destination: any View
    
    var body: some View {
        NavigationLink(destination: destination) { // Type 'any View' cannot conform to 'View'
            Text(title)
        }
    }
}

這有效:

struct Screen<Content: View>: View, Identifiable {
    var id: String {
        return title
    }
    
    let title: String
    let destination: Content
    
    var body: some View {
        NavigationLink(destination: destination) {
            Text(title)
        }
    }
}

但是這種方法的問題是我不能將不同的屏幕放入一個數組中,可以按如下方式修復:

struct AllScreens {
    var screens: [any View] = []
    
    init(){
        let testScreen = Screen(title: "Charties", destination: SwiftChartsScreen())
        let testScreen2 = Screen(title: "Test", destination: NavStackScreen())
        screens = [testScreen, testScreen2]
    }
}

但是當我嘗試訪問列表中的屏幕時,它無法在沒有類型轉換的情況下推斷出它是什么視圖。 我試圖實現的最終結果是能夠傳入一系列屏幕並將其標題顯示在如下列表中。 截屏

目前我只能通過硬編碼列表元素來實現這一點,這很有效。

import SwiftUI

struct MainScreen: View {
    let screens = AppScreens.allCases
    var body: some View {
        NavigationStack() {
            List() {
                AppScreens.chartsScreen
                AppScreens.navStackScreen
            }
            .navigationTitle("WWDC 22")
        }
    }
}

SwiftUI 是數據驅動的響應式框架,而 Swift 是嚴格類型的語言,因此我們可以讓數據負責提供相應的視圖(現在與ViewBuilder 的幫助非常簡單)。

所以這里有一個方法。 使用 Xcode 13+ / iOS 15+ 測試(NavigationView 或 NavigationStack - 這並不重要)

enum AllScreens: CaseIterable, Identifiable {   // << type !!

    case charts, navStack   // << known variants

    var id: Self { self }

    @ViewBuilder var view: some View { // corresponding view !!
        switch self {
        case .charts:
            Screen(title: "Charties", destination: SwiftChartsScreen())
        case .navStack:
            Screen(title: "Test", destination: NavStackScreen())
        }
    }
}

用法很明顯:

struct MainScreen: View {
    var body: some View {
        NavigationStack { // or `NavigationView` for backward compatibility
            List(AllScreens.allCases) {
                $0.view                 // << data knows its presenter
            }
            .navigationTitle("WWDC 22")
        }
    }
}

GitHub 上的測試模塊

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM