Двунаправленный переход SwiftUI в некоторых случаях движется в неправильном направленииIOS

Программируем под IOS
Ответить Пред. темаСлед. тема
Гость
 Двунаправленный переход SwiftUI в некоторых случаях движется в неправильном направлении

Сообщение Гость »


I have four main functional areas of my app that can be accessed by the user via a custom tab bar at the bottom of the the ContentView. I want to use a slide transition to move between the views when the user taps the desired function in the tab bar.

I also want the direction of the slide to be based on the relative position of the options on the tab bar. That is, if going from tab 1 to tab 3, the views will slide from right to left, or if going from tab 3 to tab 2, the views will slide from left to right.

This works perfectly on the first change of view and for any subsequent change of view that changes direction of the slide. E.g., the following sequence of view changes work: 1->3, 3->2, 2->4, 4->1.

However, any time there is a change of view where the direction is the same as the previous direction, it doesn't work correctly. E.g., the bolded changes in the following sequence don't work properly. 1->2, 2->3, 3->4, 4->3, 3->2.

In the above-mentioned transitions that don't work properly, the incoming view enters from the appropriate direction, but the outgoing view departs in the wrong direction. For example, the image at the bottom of this post shows the new view moving in appropriately from right to left, but the departing view is moving from left to right, leaving the white space on the left (it should also be moving from right to left along with the incoming view).

Any thoughts on why this might be happening / how to correct it?

I'm using iOS 16 for my app.

Following is a complete code sample demonstrating this issue:

import SwiftUI @main struct TabBar_testingApp: App { @StateObject var tabOption = TabOption() var body: some Scene { WindowGroup { ContentView() .environmentObject(tabOption) } } } class TabOption: ObservableObject { @Published var tab: TabItem = .tab1 @Published var slideLeft: Bool = true } enum TabItem: Int, CaseIterable { // MARK: These are the four main elements of the app that are navigated to via the custom tab or sidebar controls case tab1 = 0 case tab2 = 1 case tab3 = 2 case tab4 = 3 var description: String { switch self { case .tab1: return "Tab 1" case .tab2: return "Tab 2" case .tab3: return "Tab 3" case .tab4: return "Tab 4" } } var icon: String { switch self { case .tab1: return "1.circle" case .tab2: return "2.circle" case .tab3: return "3.circle" case .tab4: return "4.circle" } } } struct ContentView: View { @EnvironmentObject var tabOption: TabOption var body: some View { NavigationStack { VStack { // Content Group { switch tabOption.tab { case TabItem.tab1: SlideOneView() case TabItem.tab2: SlideTwoView() case TabItem.tab3: Slide3View() case TabItem.tab4: SlideFourView() } } // Use a slide transition when changing the tab views .transition(.move(edge: tabOption.slideLeft ? .leading : .trailing)) Spacer() // Custom tab bar HStack { Spacer() // Open tab 1 Button(action: { withAnimation { // Set the direction the tabs will slide when transitioning between the tabs tabOption.slideLeft = true // Change to the selected tab tabOption.tab = TabItem.tab1 } }) { VStack { Image(systemName: TabItem.tab1.icon).font(.title2) Text(TabItem.tab1.description).font(.caption2) } .foregroundStyle(tabOption.tab == .tab1 ? .primary : .secondary) .font(.title) } Spacer() // Open tab 2 Button(action: { withAnimation { // Set the direction the tabs will slide when transitioning between the tabs if tabOption.tab.rawValue == TabItem.tab1.rawValue { tabOption.slideLeft = false } else { tabOption.slideLeft = true } // Change to the selected tab tabOption.tab = TabItem.tab2 } }) { VStack { Image(systemName: TabItem.tab2.icon).font(.title2) Text(TabItem.tab2.description).font(.caption2) } .foregroundStyle(tabOption.tab == .tab2 ? .primary : .secondary) .font(.title) } Spacer() // Open tab 3 Button(action: { withAnimation { // Set the direction the tabs will slide when transitioning between the tabs if tabOption.tab.rawValue == TabItem.tab4.rawValue { tabOption.slideLeft = true } else { tabOption.slideLeft = false } // Change to the selected tab tabOption.tab = TabItem.tab3 } }) { VStack { Image(systemName: TabItem.tab3.icon).font(.title2) Text(TabItem.tab3.description).font(.caption2) } .foregroundStyle(tabOption.tab == .tab3 ? .primary : .secondary) .font(.title) } Spacer() // Open tab 4 Button(action: { withAnimation { // Set the direction the tabs will slide when transitioning between the tabs tabOption.slideLeft = false // Change to the selected tab tabOption.tab = TabItem.tab4 } }) { VStack { Image(systemName: TabItem.tab4.icon).font(.title2) Text(TabItem.tab4.description).font(.caption2) } .foregroundStyle(tabOption.tab == .tab4 ? .primary : .secondary) .font(.title) } Spacer() } // HStack closure .foregroundStyle(.blue) .padding(.top, 5) } } } } struct SlideOneView: View { var body: some View { ZStack { Group { Color.blue Text("Tab Content 1") .font(.largeTitle) .foregroundColor(.white) } } } } struct SlideTwoView: View { var body: some View { ZStack { Group { Color.green Text("Tab Content 2") .font(.largeTitle) .foregroundColor(.white) } } } } struct Slide3View: View { var body: some View { ZStack { Group { Color.purple Text("Tab Content 3") .font(.largeTitle) .foregroundColor(.white) } } } } struct SlideFourView: View { var body: some View { ZStack { Group { Color.red Text("Tab Content 4") .font(.largeTitle) .foregroundColor(.white) } } } } And finally, here's the screenshot where the bottom (departing) view is moving incorrectly from left to right which briefly leaves white space on the left, while the incoming view is correctly moving from right to left.


Изображение


HERE'S MY REVISED CODE PER COMMENTS BELOW:

class TabOption: ObservableObject { @Published var tab: TabItem = .tab1 @Published var slideLeft: Bool = true func changeTab(to newTab: TabItem) { switch newTab.rawValue { // case let allows you to make a comparison in the case statement // This determines the direction is decreasing, so we want a right slide case let t where t < tab.rawValue: slideLeft = false // This determines the direction is increasing, so we want a left slide case let t where t > tab.rawValue: slideLeft = true // This determines that the user tapped this tab, so do nothing default: return } // We have determined the proper direction, so change tabs. withAnimation(.easeInOut) { tab = newTab } } } enum TabItem: Int, CaseIterable { // MARK: These are the four main elements of the app that are navigated to via the custom tab or sidebar controls case tab1 = 0 case tab2 = 1 case tab3 = 2 case tab4 = 3 var description: String { switch self { case .tab1: return "Tab 1" case .tab2: return "Tab 2" case .tab3: return "Tab 3" case .tab4: return "Tab 4" } } var icon: String { switch self { case .tab1: return "1.circle" case .tab2: return "2.circle" case .tab3: return "3.circle" case .tab4: return "4.circle" } } } struct ContentView: View { @EnvironmentObject var tabOption: TabOption var body: some View { NavigationStack { VStack { // Content Group { switch tabOption.tab { case TabItem.tab1: SlideOneView() case TabItem.tab2: SlideTwoView() case TabItem.tab3: Slide3View() case TabItem.tab4: SlideFourView() } } // Use a slide transition when changing the tab views .transition( .asymmetric( insertion: .move(edge: tabOption.slideLeft ? .trailing : .leading), removal: .move(edge: tabOption.slideLeft ? .leading : .trailing) ) ) Spacer() // Custom tab bar HStack { Spacer() // Open tab 1 Button(action: { withAnimation { tabOption.changeTab(to: .tab1) } }) { VStack { Image(systemName: TabItem.tab1.icon).font(.title2) Text(TabItem.tab1.description).font(.caption2) } .foregroundStyle(tabOption.tab == .tab1 ? .primary : .secondary) .font(.title) } Spacer() // Open tab 2 Button(action: { withAnimation { tabOption.changeTab(to: .tab2) } }) { VStack { Image(systemName: TabItem.tab2.icon).font(.title2) Text(TabItem.tab2.description).font(.caption2) } .foregroundStyle(tabOption.tab == .tab2 ? .primary : .secondary) .font(.title) } Spacer() // Open tab 3 Button(action: { withAnimation { tabOption.changeTab(to: .tab3) } }) { VStack { Image(systemName: TabItem.tab3.icon).font(.title2) Text(TabItem.tab3.description).font(.caption2) } .foregroundStyle(tabOption.tab == .tab3 ? .primary : .secondary) .font(.title) } Spacer() // Open tab 4 Button(action: { tabOption.changeTab(to: .tab4) }) { VStack { Image(systemName: TabItem.tab4.icon).font(.title2) Text(TabItem.tab4.description).font(.caption2) } .foregroundStyle(tabOption.tab == .tab4 ? .primary : .secondary) .font(.title) } Spacer() } // HStack closure .foregroundStyle(.blue) .padding(.top, 5) } } } } Here's a GIF of the issue using the revised code (apologies for the gif compression "squashing" the screen image, but you get the idea):


Изображение



Источник: https://stackoverflow.com/questions/747 ... tain-cases
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «IOS»