使用 iPad 并将屏幕从紧凑型更改为常规型时,如何防止当前视图变为默认视图?

问题描述 投票:0回答:1
//  BottomNavigationBarView.swift
//  TrexlerLibrary
//
//  Created by Emanuel Luna on 2/3/24.
//

import SwiftUI
import UserNotifications

enum ActiveView: String, Hashable {
    case home
    case search
    case settings
}


struct MainView: View {
    @Environment(\.horizontalSizeClass) var sizeClass
    @State private var activeView: ActiveView? = .home

var body: some View {
    Group {
        if sizeClass == .compact {
            iphoneTabView
        } else {
            ipadExpansiveView
        }
    }
    .onAppear {
        InfoForLibrary().requestNotificationPermission()
    }
}

private var iphoneTabView: some View {
    TabView(selection: $activeView) {
        NavigationView { HomeView() }
            .tabItem {
                Label("Home", systemImage: "house")
            }
            .tag(ActiveView.home)
        
        NavigationView { SearchView() }
            .tabItem {
                Label("Search", systemImage: "magnifyingglass")
            }
            .tag(ActiveView.search)
        
        NavigationView { SettingsView() }
            .tabItem {
                Label("Settings", systemImage: "gear")
            }
            .tag(ActiveView.settings)
    }
}

private var ipadExpansiveView: some View {
    
    NavigationView {
        List {
            NavigationLink(destination: HomeView(), tag: ActiveView.home, selection: $activeView) {
                Label("Home", systemImage: "house")
            }
            
            NavigationLink(destination: SearchView(), tag: ActiveView.search, selection: $activeView) {
                Label("Search", systemImage: "magnifyingglass")
            }
            
            NavigationLink(destination: SettingsView(), tag: ActiveView.settings, selection: $activeView) {
                Label("Settings", systemImage: "gear")
            }
        }
        .listStyle(SidebarListStyle())
        .navigationTitle("Menu")
        
        // Render the currently selected view
        currentView
    }
}

private var currentView: some View {
    switch activeView {
    case .home:
        return AnyView(HomeView())
    case .search:
        return AnyView(SearchView())
    case .settings:
        return AnyView(SettingsView())
    case .none:
        return AnyView(HomeView())
        }
    }
}

// Preview
#Preview {
    MainView().environmentObject(UserSession())
}

这是我的主要观点。当我使用我的应用程序时,它通常会打开 HomeView,但是当我使用带有分割视图的 iPad 并将应用程序移动到紧凑尺寸或常规尺寸时,我当前所在的视图会移回到 HomeView。

如何让我的应用程序在大小发生变化时保持当前所在的视图?

swift swiftui swiftui-navigationlink swiftui-navigationview swiftui-tabview
1个回答
0
投票

此行为可能是因为

activeView
的类型与您分配给每个选项卡的
tag
的类型不同。
ActiveTab?
vs
ActiveTab
。也就是说,你写的方式
ipadExpansiveView
也是有问题的。

对于 iOS 17,您应该迁移到

NavigationStack
NavigationSplitView

首先,将标题、图像名称和每个页面的视图放入

ActiveView
枚举中。这使得从
ActiveView
值获取这些属性变得更加方便。我还制作了它
CaseIterable
,以便稍后我们可以使用
ForEach
循环遍历它的案例。

enum ActiveView: String, Hashable, CaseIterable {
    case home
    case search
    case settings
    
    var displayName: String {
        switch self {
        case .home:
            "Home"
        case .search:
            "Search"
        case .settings:
            "Settings"
        }
    }
    
    var systemImageName: String {
        switch self {
        case .home:
            "house"
        case .search:
            "magnifyingglass"
        case .settings:
            "gear"
        }
    }
    
    @ViewBuilder
    var view: some View {
        switch self {
        case .home:
            Text("Home")
        case .search:
            Text("Search")
        case .settings:
            Text("Settings")
        }
    }
}

我还会将

iPhoneTabView
iPadExpansiveView
分开
View
结构:

struct iPhoneTabView: View {
    @Binding var activeView: ActiveView
    
    var body: some View {
        TabView(selection: $activeView) {
            ForEach(ActiveView.allCases, id: \.self) { tab in
                NavigationStack { tab.view }
                    .tabItem {
                        Label(tab.displayName, systemImage: tab.systemImageName)
                    }
            }
        }
    }
}

struct iPadExpansiveView: View {
    @Binding var activeView: ActiveView
    
    var body: some View {
        NavigationSplitView {
            List(ActiveView.allCases, id: \.self, selection: Binding($activeView)) { tab in
                NavigationLink(value: tab) {
                    Label(tab.displayName, systemImage: tab.systemImageName)
                }
            }
        } detail: {
            activeView.view
        }

    }
}

NavigationSplitView
List
的选择驱动。
selection:
参数需要一个
Binding<ActiveView?>
,但是没有 no 活动视图是没有意义的,不是吗?因此,
iPadExpansiveView
采用非可选的
ActiveView
绑定,并在将其传递给
Binding<ActiveView?>
之前将其转换为
selection:

MainView
看起来像这样,具有非可选的
activeView
状态。

@Environment(\.horizontalSizeClass) var sizeClass
@State private var activeView: ActiveView = .home

var body: some View {
    Group {
        if sizeClass == .compact {
            iPhoneTabView(activeView: $activeView)
        } else {
            iPadExpansiveView(activeView: $activeView)
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.