// 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.
Как я могу заставить мое приложение оставаться в том виде, в котором я сейчас находился, при изменении размера?
На данный момент я поддерживаю iOS 17.
Я думаю, это потому, что теги вкладок не того типа, что activeView. Попробуйте изменить .tag(ActiveView.home) на .tag(Optional.some(ActiveView.home)) и сделайте то же самое для каждого тега вкладки.





Вероятно, такое поведение связано с тем, что тип activeView отличается от типов tag, которые вы назначили каждой вкладке. ActiveTab? против 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 и iPadExpansiveViews отдельными 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?>, но отсутствие активного просмотра не имеет смысла, не так ли? Таким образом, 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)
}
}
}
Это сработало! Интересно, можно ли было бы сделать это с другими видами? Например, в SettingsView есть список с кнопкой «О программе». Когда я нажимаю на него, я перехожу к другому представлению, которое все еще находится в SettingsView.
@EMAN-GAMING Конечно. Я думаю, вам следует поискать «навигацию на основе значений» в качестве отправной точки. Если вы застряли, вы можете опубликовать новый вопрос и включить минимально воспроизводимый пример, как вы это сделали здесь.
Какие версии iOS вы поддерживаете? Можете ли вы вместо этого использовать
NavigationStack?