Comments (7)
I couldn't figure it out after some hours of debugging so I posted a question on StackOverflow. Hopefully, someone can figure it out as it would make your library perfect for my use case :)
from swiftui-navigation-stack.
Hi @ln-12, the problem here is due to the if-else
statement in the SecondView
. The transition between the ProgressView
and the Text
(there's always a transition in SwiftUI when you write an if-else
like that) conflicts somehow with the screen transition. You can try to fix it by removing the else
branch:
struct SecondView: View {
@EnvironmentObject var viewModel: ViewModel
var body: some View {
VStack(alignment: .center) {
HStack { Spacer() }
Spacer()
if(viewModel.someText.isEmpty) {
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
}
Text(viewModel.someText)
Spacer()
}
.background(Color.red)
}
}
from swiftui-navigation-stack.
Yeah, I already noticed that. Unfortunately, my real UI is much complexer (I have multiple else branches), so that this won't work.
So you think this is a SwiftUI problem and not specific to your library, right?
from swiftui-navigation-stack.
Well... basically yes. It depends on how SwiftUI manages the if-else
transition in those cases. In your example you have two if-else
transitions "overlapping" (the one involving the screens and the one involving the content of the SecondView
). The second transition is not performed correctly. But it doesn't strictly depends on the navigation stack. Take a look at this simple example (it's basically your example without the navigation stack):
@main
struct MyApp: App {
@StateObject private var viewModel = ViewModel()
@State private var push = false
private let transition = AnyTransition.asymmetric(insertion: .move(edge: .trailing),
removal: .move(edge: .leading))
private let transitionAnimation = Animation.easeOut(duration: 3)
var body: some Scene {
WindowGroup {
if !push {
VStack(alignment: .center) {
HStack { Spacer() }
Spacer()
Button(action: {
push.toggle()
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 0.2) {
DispatchQueue.main.sync {
self.viewModel.someText = "Test ### Test ### Test ### Test ### Test ### Test ###"
}
}
}){
Text("Go")
}
Spacer()
}
.background(Color.green)
.transition(transition)
.animation(transitionAnimation)
} else {
SecondView()
.transition(transition)
.animation(transitionAnimation)
.environmentObject(viewModel)
}
}
}
}
final class ViewModel: NSObject, ObservableObject {
@Published var someText: String = ""
}
struct SecondView: View {
@EnvironmentObject var viewModel: ViewModel
var body: some View {
VStack(alignment: .center) {
HStack { Spacer() }
Spacer()
if(viewModel.someText.isEmpty) {
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
} else {
Text(viewModel.someText)
}
Spacer()
}.background(Color.red)
}
}
As you can see the bug still occurs:
We should try to fix the issue in this example (without the navigation stack) and then see if we can improve the navigation stack by integrating the fix directly into it.
from swiftui-navigation-stack.
I got the following working by using the TabView
element. The big downside is that animations can't be customized, so only the default tab view page switching animation can be used. I am not sure why the transition is ignored and I can't get a working implementation of a custom TabViewStyle
. It would be so much easier if Apple would open source stuff like Google does for Android (or simply provide a working native navigation).
@main
struct TransitionTestApp: App {
@StateObject private var viewModel = ViewModel()
var body: some Scene {
WindowGroup {
ContentView().environmentObject(viewModel)
}
}
}
struct ContentView: View {
@EnvironmentObject var viewModel: ViewModel
private let transition = AnyTransition.asymmetric(insertion: .move(edge: .top),
removal: .move(edge: .bottom))
private let transitionAnimation = Animation.easeOut(duration: 3)
var body: some View {
VStack {
TabView(selection: $viewModel.selectedTab) {
FirstView()
.tag(0)
.transition(transition)
.animation(transitionAnimation)
SecondView()
.tag(1)
.transition(transition)
.animation(transitionAnimation)
}
.onAppear(perform: {
UIScrollView.appearance().bounces = false
})
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
.transition(transition)
.animation(transitionAnimation)
}
}
}
struct FirstView: View {
@EnvironmentObject var viewModel: ViewModel
var body: some View {
VStack(alignment: .center) {
HStack { Spacer() }
Spacer()
Button(action: {
withAnimation {
viewModel.selectedTab += 1
}
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 0.2) {
DispatchQueue.main.sync {
self.viewModel.someText = "Test ### Test ### Test ### Test ### Test ### Test ###"
}
}
}){
Text("Go")
}
Spacer()
}
.background(Color.green)
}
}
final class ViewModel: NSObject, ObservableObject {
@Published var someText: String = ""
@Published var selectedTab = 0
}
struct SecondView: View {
@EnvironmentObject var viewModel: ViewModel
var body: some View {
VStack(alignment: .center) {
HStack { Spacer() }
Spacer()
if(viewModel.someText.isEmpty) {
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
} else {
Text(viewModel.someText)
}
Spacer()
}.background(Color.red)
}
}
from swiftui-navigation-stack.
Using the SwiftUIPager library, it works as intended! I don't know why the content is looking correct in this library, but not in yours. Maybe you can have a look what they are doing different.
import SwiftUI
import SwiftUIPager
@main
struct TransitionTestApp: App {
@StateObject private var viewModel = ViewModel()
var body: some Scene {
WindowGroup {
ContentView().environmentObject(viewModel)
}
}
}
struct ContentView: View {
@EnvironmentObject var viewModel: ViewModel
var items = Array(0..<2)
var body: some View {
Pager(
page: viewModel.page,
data: items,
id: \.self
) { index in
if(index == 0) {
FirstView()
} else if(index == 1) {
SecondView()
}
}
.bounces(false)
.draggingAnimation(.standard)
}
}
struct FirstView: View {
@EnvironmentObject var viewModel: ViewModel
private let transitionAnimation = Animation.easeOut(duration: 3)
var body: some View {
VStack(alignment: .center) {
HStack { Spacer() }
Spacer()
Button(action: {
withAnimation(transitionAnimation) {
viewModel.page.update(.next)
}
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 0.2) {
DispatchQueue.main.sync {
self.viewModel.someText = "Test ### Test ### Test ### Test ### Test ### Test ###"
}
}
}){
Text("Go")
}
Spacer()
}
.background(Color.green)
}
}
final class ViewModel: NSObject, ObservableObject {
@Published var someText: String = ""
@Published var page: Page = .first()
}
struct SecondView: View {
@EnvironmentObject var viewModel: ViewModel
var body: some View {
VStack(alignment: .center) {
HStack { Spacer() }
Spacer()
if(viewModel.someText.isEmpty) {
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
} else {
Text(viewModel.someText)
}
Spacer()
}.background(Color.red)
}
}
With this approach you also get the "swipe to go back" behavior discussed in issue #8
from swiftui-navigation-stack.
I did a quick implementation with your library here: https://github.com/ln-12/swiftui-navigation-stack/tree/animation-fix
With this approach, you have to set your rootView
like this:
NavigationStackView(navigationStack: self.navigationStack) {}
.onAppear(perform: {
self.navigationStack.push(RootView())
})
With that, I get the right push animations in all cases and also have the "swipe to go back" gesture. It's far from perfect, other animations might not work, but it is exactly want I was looking for. Maybe you find a way to properly integrate it or it might just help someone else who is looking for this functionality. You can also tell me how you would integrate it so that I can create a pull request :)
from swiftui-navigation-stack.
Related Issues (20)
- Stack Reset / Jump to a completely different view HOT 2
- Transition animation not working HOT 1
- @State variables get reset after pop HOT 3
- Support for iOS 15. HOT 1
- Push doesn't work if app is backgrounded and aware of scenePhase
- Return to the same position in the previous view HOT 2
- Support for Xcode 14 and new SwiftUI API HOT 6
- Previous view completely reloaded after pop HOT 1
- Popping to a specific view
- Callback navigation sometimes doesnt work HOT 1
- iOS 16 transitions malfunctioning HOT 9
- after pop,the previous scrollview auto scroll to top? HOT 6
- Xcode 14 Compiling Issue HOT 6
- not support swipe back HOT 2
- Referencing @Environment(\.scenePhase) var scenePhase breaks navigation when moving app to background
- [Bug]: Clicking on any other window in macOS will return stack to its root
- Value not changed by @Binding
- onappear excuse only first time
- how use in List cell
- after pop,the previous scrollview auto scroll to top?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from swiftui-navigation-stack.