I have an app that is using a timer to scroll programmatically between views on the onboarding screen. From the onboarding screen, I can go to login then signup screen (or profile then my account screen). In both ways, when opening the login screen and clicking on signup, the signup screen appears but then disappears and takes me back to login (The same happens when I try to enter My Account screen from the profile screen). Check please the gif attached.
I've searched all around the web without finding any similar issue.
Note: I am using NavigationLink to navigate between screens, and I tried also to use both Timer, and Timer.TimerPublisher leading me to the same result, the screens will crash once the timer fires.
Note: When removing the timer (or the code inside onReceive) everything works fine. I also suspect that the issue could be related to menuIndex
struct OnboardingView: View {
//MARK: - PROPERTIES
@State var menuIndex = 0
@State var openLogin = false
let timer = Timer.publish(every: 4, on: .main, in: .common).autoconnect()
//MARK: - BODY
var body: some View {
NavigationLink(destination: LoginView(), isActive: $openLogin) {}
VStack (spacing: 22) {
ProfileButton(openProfile: $openLogin)
.frame(maxWidth: .infinity, alignment: .trailing)
.padding(.horizontal, 22)
OnboardingMenuItem(text: onboardingMenu[menuIndex].title, image: onboardingMenu[menuIndex].image)
.frame(height: 80)
.animation(.easeInOut, value: menuIndex)
.onReceive(onboardingVM.timer) { input in
if menuIndex < onboardingMenu.count - 1 {
menuIndex = menuIndex 1
} else {
menuIndex = 0
}
}
...
}
}
}
CodePudding user response:
You can only have one detail NavigationLink
, if you want more you have to set isDetailLink(false)
, this is why you are seeing the glitch. Alternatively if you don't require the split view behaviour you can use .navigationViewStyle(.stack)
. Note in iOS 16 this is replaced with NavigationStackView
.
FYI a timer needs to be @State
or it will start from zero every time that View is init, e.g. on a state change in the parent View
causing its body to be invoked. Even better is to group the related properties into their own struct, e.g.
struct OnboardingViewConfig {
var menuIndex = 0
var openLogin = false
let timer = Timer.publish(every: 4, on: .main, in: .common).autoconnect()
// mutating func exampleMethod(){}
}
struct OnboardingView: View {
@State var config = OnboardingViewConfig()
...