Giter VIP home page Giter VIP logo

swiftui-navigation-stack's People

Contributors

503geek avatar matteopuc avatar mattevigo avatar mustafaozhan avatar pacu avatar piterwilson avatar sadmansamee avatar saket avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swiftui-navigation-stack's Issues

popping a view makes the previous view non clickable

I have a home screen with 3 Tabs one of the tab has scroll view with some clickable items, on pushing this navigation view stack, and popping back the view remains non-clickable unless the scroll is moved a little and then everything is back to clickable again.

HELP!

warning emitted: CGAffineTransformInvert: singular matrix

I get following warning when pushing or popping from NavigationStack
[90654:2639075] [Unknown process name] CGAffineTransformInvert: singular matrix.
Am I doing something wrong here:

        PushView(destination:SettingsView()) {
          VStack {
            Image(systemName: "gear")
              .resizable()
              .scaledToFit()
              .clipShape(Rectangle())
              .shadow(color: .primary, radius: 5)
              .padding([.horizontal, .top], 7)
            Text("Settings").lineLimit(1)
          }
          .frame(minWidth: 50, maxWidth:100, alignment: .center)
        }

          PopView {
            Text("<-")
          }

PushView with Buttons

How do I PushView with buttons...??

This does nothing..
PushView(destination: SignInView()) { Button(action: { self.isActive.toggle() }) { HStack { Image("mail-icon") Text(" Login with Email/Mobile") .font(.custom("Avenir Next Bold", size: 14.0)) Spacer() } } .modifier(PrimaryButton(colorInput: .red)) }

But this works fine..??

PushView(destination: SignInView()) { HStack { Image("mail-icon") Text(" Login with Email/Mobile") .font(.custom("Avenir Next Bold", size: 14.0)) Spacer() } .modifier(PrimaryButton(colorInput: .red)) }

PopView doesn't work for me (Xcode 11.3.1)

Hello,
I've been trying your awesome navigation stack and it's been great to push the views, but I couldn't manage to make to PopView work ( it doesn't send me to the previous view even when I set an Id ) I honestly don't know what am doing wrong.

ParentView where I use the PushView ( works fine )
ScrollView(.horizontal, showsIndicators: false) { HStack (spacing: 16){ ForEach(productData){ item in PushView(destination: ProductDetails()){ SingleProduct(showCount: false, count: 01, countnull: false, singleProduct: item) } } }.frame(height: 320) .padding(.top,20) .padding(.horizontal) } .offset( y: -15)
`

ChildView ( Doesn't work )

HStack{ PopView(isActive: $isActive){ Button(action: { self.isActive.toggle() }){ Image(systemName: "arrow.left") .font(.system(size: 24, weight:.regular, design: .default)) .foregroundColor(Color.black) .frame(width:45,height: 45) .background(Color.white) .cornerRadius(13) .shadow(color: Color.black.opacity(0.1), radius: 10, x: 0, y: 12) } } } .padding(.horizontal,16)

ViewStack not persistent

Hi, thanks for this nice implementation. I've bumped into a problem. I have the rootView which is made out of some bottom view and navigationViewStack. The bottom view needs to be displayed over some of the navigation stack, but not all of them. This rootView has a viewModel that controls the visibility of the bottom view and can be shared down the stack. After I navigate through the stack, when modifing the rootView viewModel the whole stack is reseting and the rootview is displayed. I think this is because of ViewStack is reinitialized. Making it persistent per navigation stack instance should resolve these kind of issues.

P.S. : I've resolved this issue by making a singleton of HashMaps [id: NavigationStack] and a methode to get/add a new NavigationStack singletone inside NavigationStack class. The hashmap for maintaining the functionality of multiple navigations flow. Every navigation flow will have an id and from here it's own NavigationStack singletone. Inside the NavigationStackVIew init also ask for an id with the default "root" if it's not specified.

Also if you have a more elegant/efficient way of achieving this, please let me know.

Navigation bar

Hi!

This is some impressive work! Thanks for that!

We are really facing lots of issues with the NavigationView comes with SwiftUI and looking for an alternative, the problem is that we do need the option to add a "Back" button to views, similar to the way native NavigationView let you.

Is there any example of how to do so? or maybe while using another library that provides a drop-in bar?

Thanks again!

[Unknown process name] CGAffineTransformInvert: singular matrix

First off, your utility is AMAZING! Thank you so much for this! I'm running into the following warning/error:

2020-07-04 08:37:50.344351-0400 NavStackTest[11370:1800054] [Unknown process name] CGAffineTransformInvert: singular matrix.
2020-07-04 08:37:50.344494-0400 NavStackTest[11370:1800054] [Unknown process name] CGAffineTransformInvert: singular matrix.
2020-07-04 08:37:50.365485-0400 NavStackTest[11370:1800054] [Unknown process name] CGAffineTransformInvert: singular matrix.
2020-07-04 08:37:50.561570-0400 NavStackTest[11370:1800054] [Unknown process name] CGAffineTransformInvert: singular matrix.
2020-07-04 08:37:52.577640-0400 NavStackTest[11370:1800054] [Unknown process name] CGAffineTransformInvert: singular matrix.
2020-07-04 08:37:52.779411-0400 NavStackTest[11370:1800054] [Unknown process name] CGAffineTransformInvert: singular matrix.
2020-07-04 08:37:52.779592-0400 NavStackTest[11370:1800054] [Unknown process name] CGAffineTransformInvert: singular matrix.

After doing some digging, it seems to be originating from specifying the transitionType attribute for the NavigationStackView while having a List view inside the destination. If I leave this attribute out, there are no errors. Also, I'm not sure if this is related to an already closed issue #22. It would be greatly appreciated if you can help. Thank you in advance. Please see reproducible code see below:

import SwiftUI
import NavigationStack

struct ContentView: View {
  var body: some View {
    NavigationStackView(transitionType: .custom(.scale)) {
      ZStack {
        Color.orange.edgesIgnoringSafeArea(.all)
        HStack {
          PushView(destination:ChildView()) {
            Text("Settings")
          }
        }
      }
    }
  }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}

struct ChildView: View {
  @State var appName: String = ""
  var body: some View {
    ZStack {
      Color.yellow.edgesIgnoringSafeArea(.all)
      
      VStack {
        List {
          ForEach(0...10, id: \.self) { i in
            ListRow(item: "One")
          }
        }
        
        PopView { Text("Go Back") }
      }
    }
  }
}

struct ListRow: View {
  @State var item: String
  var body: some View {
    Text(self.item)
  }
}

SceneDelegate .environmentObject

For programmatic push we need:

@EnvironmentObject private var navigationStack: NavigationStack

But this results in this error (which is normal):

A View.environmentObject(_:) for NavigationStack may be missing as an ancestor of this view

The normal fix for this, in the root view or a parent view, as I understand it, is to init and "attach" the bindable like this (such as in SceneDelegate):

var navigationStack = NavigationStack()

let contentView = SomeView().environmentObject(navigationStack)

But this gives the compiler error:

'NavigationStack' initializer is inaccessible due to 'internal' protection level

How did you work around this in your examples for programmatic push? Is there another way to attach the env obj other than initializing it?

Collapsed sidebar change side bar link cause crash

Steps to reproduce:

  1. Enter full screen.
  2. Collapse the sidebar by dragging it all the way to the left.
  3. Let the mouse go.
  4. Move the mouse left until the sidebar appears as overlay.
  5. Select another sidebar tab -> crash

Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1a4503df8)

Clear Stack feature

Maybe an implementation of a function that clears the ViewStack

When called it will :

  • Set the last view as Root View
  • Clear the stack

Question: How to change transition of the view which was already pushed into nav stack

First of all thanks for the great library! Am trying to figure out how to achieve different transitions on a view which was already pushed to the stack. Let's say i pushed a view with a default transition and on the view there are two buttons: one is leading to the next screen with a default transition but the other is showing a view over the current like a popover. Because the host view is already pushed to the stack with defined push and pop transition i cannot see a way how to modify it for my needs. Any ideas are appreciated! Thanks!

use of performBackgroundActivities in viewmodel

I can not apply this logic, could you give me an example of how to apply it, I need to manage the screen transactions through my viewmodel.

struct MyHome: View {
    @ObservedObject var viewModel: ViewModel
    @EnvironmentObject private var navigationStack: NavigationStack

    var body: some View {
        Button(action: {
            self.viewModel.performBackgroundActivities(withCallback: {
                DispatchQueue.main.async {
                    self.navigationStack.push(ChildView())
                }
            })
        }, label: {
            Text("START BG ACTIVITY")
        })
    }
}

No ObservableObject of type NavigationStack found. A View.environmentObject(_:) for NavigationStack may be missing as an ancestor of this view.

Fantastic library.

What I did:

  • I created a NavigationViewModel that will handle navigation across pages that need it. See NavigationVM below.
  • Programmatically want to push to the next view while providing the viewId

Error:
No ObservableObject of type NavigationStack found. A View.environmentObject(_:) for NavigationStack may be missing as an ancestor of this view.

Thank you for your help.

import Foundation
import SwiftUI
import NavigationStack

class NavigationVM: ObservableObject {
    @EnvironmentObject private var navigationStack: NavigationStack
    
    init(){
        
    }
    
    func pushView(view: AnyView, viewId: String? = nil){
        DispatchQueue.main.async {
            if viewId?.isEmpty == true {
                self.navigationStack.push(view)
            } else {
                self.navigationStack.push(view, withId: viewId!)
            }
        }
    }
    
    func popView(viewId: String? = nil){
        DispatchQueue.main.async {
            if viewId?.isEmpty == true {
                self.navigationStack.pop()
            } else {
                self.navigationStack.pop(to: PopDestination.view(withId: viewId!))
            }
        }
    }
    
    func popToRoot() {
        DispatchQueue.main.async {
            self.navigationStack.pop(to: .root)
        }
    }
}

Here's my implementation:

var body: some View {
        NavigationStackView {
              merchantGroupsBody()
        }
}

private func merchantGroupsBody() -> some View {
        VStack{
            ForEach(exploreVM.merchantGroups) { merchantGroup in
                if merchantGroup.merchants.count > 0 {
                    VStack (alignment: .leading){
                        merchantGroupHeaderBody(merchantGroup)
                        ScrollView(.horizontal){
                            HStack{
                                ForEach(merchantGroup.merchants, id: \.self){ merchant in
                                    merchantBody(merchant)
                                }
                            }
                        }
                    }
                    //.foregroundColor(.white)
                }
            }
        }
    }

private func merchantBody(_ merchant: Merchant) -> some View {
        var alreadyCached: Bool {
            ImageCache.default.isCached(forKey: merchant.locationImageUrl)
        }
        
        return
            //NavigationLink(destination: MerchantView(MerchantVM(merchant))) {
            VStack (alignment: .leading) {
                KFImage(URL(string: merchant.attachments.first!.url))
                    .onSuccess { r in
                        print("Success: \(merchant.name) - \(r.cacheType)")
                    }
                    .onFailure { e in
                        print("Error for mechant: \(merchant.name): \(e)")
                    }
                    .onProgress { downloaded, total in
                        print("\(downloaded) / \(total))")
                    }
                    .placeholder {
                        HStack {
                            Image(systemName: "arrow.2.circlepath.circle")
                                .resizable()
                                .frame(width: 50, height: 50)
                                .padding(10)
                            Text("Loading...").font(.title)
                        }
                        .foregroundColor(.gray)
                    }
                    .cancelOnDisappear(true)
                    .resizable()
                    .frame(width: 200, height: 100)
                    .aspectRatio(contentMode: .fill)
                    .opacity(doneLoadingImage || alreadyCached ? 1.0 : 0.3)
                    .animation(.linear(duration: 0.4))
                Text(merchant.name)
                Text("\(merchant.distanceToCustomerString) | \(merchant.hoursOfOperationString)")
                    .font(.system(size:12))
                Spacer()
            }
            .onTapGesture {
                navigationVM.pushView(view: AnyView(MerchantView(MerchantVM(merchant))), viewId: CustomerViewIds.MerchantView.rawValue)
            }
        //}
    }

TextField or UITextView Representable not working

If you have any TextField or a UITextView Representable object in any view that is inside NavigationStack, user is prevented from typing anything. The text just disappears.

e.g.
TextField("test", text: $workingText)

PushView/PopView define their own animation

Hi,

I may be missing something obvious, or not fully understanding the use of this library, but I'd like for different PushView and PopView (and their programmatic counterparts) to allow for overriding the default animation of the entire stack.

Is that something that is possible today? It doesn't seem to appear so from the code, where it uses withAnimation(easing). Is it recommended to create a new NavigationStackView whenever you want to change the animation style?

Thanks!

Fatal error: No observable object of type NavigationStack.Type found (iOS 13.0)

Hello there!

First of all, thank you for this amazing library which fixed many problems we had while implementing a navigation stack on our own, e.g. when using conditional navigation via switch-case-statements.

While this library is working completely fine on iOS 13.1, 13.2.2 and 13.3, it leads to the following crash during app start on iOS 13.0:

Fatal error: No observable object of type NavigationStack.Type found. A View.environmentObject(_:) for NavigationStack.Type may be missing as an ancestor of this view.: file /BuildRoot/Library/Caches/com.apple.xbs/Sources/Monoceros_Sim/Monoceros-24.4/Core/EnvironmentObject.swift, line 161 Fatal error: No observable object of type NavigationStack.Type found. A View.environmentObject(_:) for NavigationStack.Type may be missing as an ancestor of this view.: file /BuildRoot/Library/Caches/com.apple.xbs/Sources/Monoceros_Sim/Monoceros-24.4/Core/EnvironmentObject.swift, line 161 (lldb)

There seems to be a problem with attaching NavigationStack as an EnvironmentObject. We were able to fix this issue by setting it as an EnvironmentObject by our own. This though is not possible with the library as it is, since its initializes is internal and therefor not accessible.

My question is now how to fix this issue on iOS 13.0. If there is no solution, maybe you could provide a public initializer as a workaround, so we can add the EnvironmentObject by our own.

Thanks in advance and best regards,
Philipp

Swipe from left to right to go back

Trying to implement a custom navigation as the NavigationView that SwiftUI supports doesnt provide many features,

Notice the one in here is quite impressive. But I noticed this doesnt have the feature to go back to the previous screen by dragging left to right (default go back feature that iOS provides)

Is there a way to get it done ?

Transition animation not working

I've successfully removed the slide animation but now no animation is working when I transition between view. Ideally the MainMenu screen would fade in after the text from the first view is gone.

struct ContentView: View {
	var body: some View {
		NavigationStackView(transitionType: .custom(.opacity), easing: .easeOut(duration: 2)) {
			IntroScreen()
		}
	}
}

struct IntroScreen: View {
	@State private var start = true
	@State private var accelerate = false
	@State private var change = false
	@State private var counter = 0

	let timer = Timer.publish(every: 1.5, on: .main, in: .common).autoconnect()

	var body: some View {
		VStack {
			Text("Sick library bro")
				.font(.system(size: 35))
				.offset(x: 0, y: (start ? -500 : 0))
				.animation(.easeOut(duration: 1.5))
				.opacity((accelerate ? 0 : 1))
				.animation(.easeIn(duration: 1))
				.onAppear() {
					start = false
				}
				.onReceive(timer){ _ in
					if counter < 1 {
						accelerate = true
					} else {
						change = true
					}
					counter += 1
				}

			PushView(destination: MainMenu(), isActive: $change) {}
		}

	}

}

MainMenu:

struct MainMenu: View {
	var body: some View {
		VStack {
			Color.blue.edgesIgnoringSafeArea(.all)
			Text("hi")
				.font(.system(size: 35))
		}
	}
}

This is what I get

ezgif com-gif-maker

[Suggestion] Drag gestures

Hi,

I'd love to see a really great future of standard NavigationView, such as drag gesture for going back, It's relatively easy to do

sheets stop showing

after changing the parent of a view from NavigationView to NavigationStackView sheets no longer work inside its children eg:

struct ChildView: View {
    @State var showPopup = false
    var body: some View {
        Text("test")
            .onTapGesture { self.showPopup = true }
            .onAppear { self.showPopup = true }
            .sheet(isPresented: self.$showPopup) { Text("popup") }
    }
}

popup is never shown, if I revert back to NavigationView it works fine.

Pushing to certain view after Push notification received

Hello, great library!
I was wondering if you have any suggestion or example to use it to push a view after a push notification is received from AppDelegate.
I tried to push the view like this:
self.appState.navigationStack?.push((MyView()))
But apparently it cannot be done, unless you trigger the push from a View/button.
Thank you!

onAppear called immediately after push/pop

Hi there,

First, thanks for this stack, really useful for my small side project as a SwiftUI rookie.

Actually, I've just encountered the following behavior: onAppear is called immediately when pushing/popping pages, and not when the transition is finished. As I have an advanced custom transition taking more time and leading to a page that will have its own animation, I would like onAppear to be delayed until the transition is finished.

I believe this is not really a bug but I'm wondering if this could be solved by this stack. Note: I can probably use state and enhance my custom transition to workaround (even though tbh custom transitions are a bit buggy when I want to deal with timing/delays).

Here is a simple example:

struct DestinationView: View {
    var body: some View {
        VStack {
            Spacer()
            HStack {
                PopView {
                    Text("Page 2").onAppear {
                        print("Page 2 onAppear") // Printed immediately
                    }
                }
            }
            Spacer()
        }
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
    }
}

struct Transition_Previews: PreviewProvider {
    static var previews: some View {
        VStack {
            NavigationStackView(transitionType: .default,
                                easing: Animation.linear(duration: 5)) {
                                    PushView(destination: DestinationView()) {
                                        HStack {
                                            Spacer()
                                            Text("Page 1").onAppear {
                                                print("Page 1 onAppear") // Printed immediately
                                            }
                                            Spacer()
                                        }
                                    }
            }
        }
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
    }
}

navViewModel not persisted

This might be due to my limited knowledge of SwiftUI or a flaw in my app. However, it happens that NavigationStackView is re-initialized for rerendering and because navViewModel is created in the constructor, it forgets its state.

Marking it is a @StateObject fixes the problem for me, but this method is only available starting iOS 14, so I'm not sure if that's what you want for this library.

And as I mentioned, perhaps NavigationStackView shouldn't be reinitialized at all, but that seems to be a problem with either SwiftUI or my app.

Stack Reset / Jump to a completely different view

Thanks for this project!
I'm interested in the following functionality:
Consider, we have a list of views in the stack: [Z, A, B, C]
I'd like to reset stack completely to have new view hierarchy as [Z, X] by e.g. pressing a button in the view C.
Is this possible as of right now?

Fast Forward

Hi, awesome work here.
I wonder how to navigate programmatically to any view in hierarchy, but not just popping to a previous one also pushing a far view.
I have a navigation mechanism that should be able to navigate from any view to any other view keeping stack. Useful to use with deep links for example, which I need. It was working fine until found some issues in SwiftUI for certain routes.
So, is this possible now? Maybe a navigationStack.push([View]) Perhaps View should conform to protocol Identifiable ....
Example:
I have a view targetView which can be reached by this route: [root, view1, view2, targetView]
I'm currently in another view currentView which route could be like [root, view1, view3, currentView]
I ned to go from currentView to targetView in seamless way but keeping stack, so I don't want to view how it animates popping to view1and then pushing view2 and after that targetView.

Thanks in advance!

Cocoapod support

Could you also add this to cocoapods, for those who haven't yet migrated to SPM? :)

Incompatibility with macOS through cocoapods

Hey, thanks for maintaining this library! I am running into this error when trying to import it into my macOS app through cocoapods:

[!] The platform of the target `Teleport` (macOS 11.0) is not compatible with `NavigationStack (1.0.2)`, which does not support `macOS`.

What am I missing?

Broken behavior when the view is changing during animation

First of all: thanks for that awesome library! It's so much better that what is currently available in SwiftUI!

Now to describe the actual problem: when I am navigating between static views, everything works just fine. But as soon as a view is changing, it is not animated anymore. This does not happen when the text of a Text() view is changing for example. It only occurs when a view is replaced during the transition, like when showing a ProgressView() and switching to the Text() once the content is available. The error looks like this during the animation:

EE7DE9D6-3CCE-4F02-874C-415268FB41DC

The Text() should be fully contained within the red area, but as you can see, it is located where it should be after the transition. I setup a minimal working example below. The transition is slowed down to visualize the error. The asyncAfter operation stands for some network request.

@main
struct MyApp: App {
    @StateObject private var viewModel = ViewModel()
    @StateObject var navigationStack = NavigationStack(easing: Animation.easeOut(duration: 3))

    var body: some Scene {
        WindowGroup {
            NavigationStackView(navigationStack: navigationStack) {
                VStack(alignment: .center) {
                    HStack { Spacer() }
                    Spacer()
                                        
                    Button(action: {
                        self.navigationStack.push(SecondView())
                        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)
            }.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)
    }
}

Is it possible to fix this? I can only load the content, after the user taps the button which starts the transition. If not, the only idea which comes to my mind is that any view updates could be delayed until the transition is finished.

Pop to previous (back button)?

Hello guys, tanks for sharing such a needed library!

Is it possible to do a Pop to previous (back button), instead of "Pop to root"?

cheers form Stockholm!

Navigation with matchedGeometryEffect?

Ciao Matteo!

Is it possible to do a navigation with scaling animation using matchedGeometryEffect?

On the example bellow I made it work with a Stack, works fine. But I cannot get it to work as a navigation between views.

Maybe there is already a way to do using your library?

cheers from Stockholm!

import SwiftUI


class CoverData: ObservableObject {
    @Published var images = ["cover", "cover2"]
    @Published var selected = ""
    @Published var showDetails: Bool = false
}

struct Grid: View {
    @EnvironmentObject var viewModel: CoverData
    
    let namespace: Namespace.ID
    
    var body: some View {
        
        List {
            ForEach(viewModel.images.indices) { index in
                let image = viewModel.images[index]
                Image(image)
                    .resizable()
                    .frame(width: 50, height: 50)
                    .cornerRadius(4)
                    .padding()
                    .matchedGeometryEffect(id: image, in: namespace)
                    .onTapGesture {
                        viewModel.selected = image
                        withAnimation(.spring()) {
                            viewModel.showDetails.toggle()
                        }
                    }
            }
        }
   }
}

struct Detail: View {
    @EnvironmentObject var viewModel: CoverData

    let namespace: Namespace.ID
    
    var body: some View {
        
            Image(viewModel.selected)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .cornerRadius(10)
                .padding(40)
                .matchedGeometryEffect(id: viewModel.selected, in: namespace)
        
      
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color(#colorLiteral(red: 0.234857142, green: 0.043259345, blue: 0.04711621255, alpha: 1)))
    }
}

struct ContentView: View {
    
    @Namespace private var ns
    @StateObject private var coverData = CoverData()
    
    var body: some View {
        ZStack {
            Spacer()
            if coverData.showDetails {
                Detail(namespace: ns)
                .onTapGesture {
                    withAnimation(.spring()) {
                        coverData.showDetails.toggle()
                    }
                }
            }
            else {
                Grid(namespace: ns)
            }
        }
        .environmentObject(coverData)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

How is viewId determined when PopView is used?

I'm using your NavigationStack in combination with SwiftUI's default Tabbed app, with each tab having its own NavigationView. I have wrapped the entire app's ContentView into NavigationStackView so that I can display **PushView()**s in fullscreen mode, including over the Tab bar. My question is where do I specify/define the viewId for the nested view that I would like to PopView() back to? Documentation provides a vague example of how to supply destinationId of the ChildView() when PushView() is used but I have a hard time understanding how the passed on childViewId helps in popping back to the parent or maybe a view nested 2 levels inside NavigationView? Can you please clarify or provide a slightly complex example? Thank you again!

Programmatically navigation does not work on simulator or physical device with iOS 14.5

On a simulator with iOS 13.0, programmatically navigation works fine, but on the same simulator with iOS 14.5 and on a physical device with iOS 14.5, the transition does not work. With what it can be connected?

// First View
@EnvironmentObject var navigationStack: NavigationStack
//...
DispatchQueue.main.async {
    let destination = ModelDetailContainerView()
        .environmentObject(appStore)
        .environmentObject(navigationStack)
    self.navigationStack.push(destination)
}

// Second View
@EnvironmentObject var navigationStack: NavigationStack

var body: some View {
    ModelDetailRenderView(item: detailedSelectedItem)
        .valueChanged(value: detailedSelectedItem.wrappedValue) { value in
            if value == nil {
                navigationStack.pop(to: .root)
            }
        }
}

UPD
Transition occurs by tap on the context menu item of custom cell. Programmatic behavior of all interested entities does not change depending on iOS version.

NavigationBar not presented

Hi,

I really miss the possibility to add custom transitions in swiftui. So thank you for working on this framework.
Unfortunatly if I switch from NavigationView to NavigationStackView the navigationbar disappears.

NavugationBar Title

hi
how I can mimic the navigation bar functionality in the navigation stack.how I can add navigation title and navigation Buttons and background color. should I use the ViewModifier to add headView to handler the navigation title and .. and another ContentView to render the body
best regards

Fatal error: No ObservableObject of type NavigationStack found.

Open curiosity: Is there a way to use this inside of a modal or nav view? (Works well otherwise)

If I attempt either, I get the following error:

Fatal error: No ObservableObject of type NavigationStack found.

I'm down to try anything as a potential workaround

Default UINavigationController animation?

Hi, quick question - how do I replicate the default NavigationView's transition animation?

It's not a plain .slide, it's both slide and slide of the original one at a half distance.

Mandatory pops to the root view when modifying observed object in the stacked view

Hi, this one of the great library I ever found. However when trying to modifying an observed object in the second view (stack view), then it pop to the root view immediately, here is the minimum code to reproduce the issue, please have a look:

import SwiftUI
import NavigationStack

class Model : ObservableObject {
    @Published var counter1 : Int = 0
    @Published var counter2 : Int = 0
}

struct SecondView: View {
    @ObservedObject var model : Model
    
    var body: some View {
        VStack() {
            Text("2st Page")
            Button(action: {
                model.counter2 += 1
                print(model.counter2)
            }, label: {
                Text("Press to increase (\(model.counter2))")
            })
            PopView(label: {
                Text("Back")
            })
        }
    }
}

struct ContentView: View {
    @ObservedObject var model : Model = Model()
    
    var body: some View {
        NavigationStackView() {
            VStack() {
                Text("1st Page")
                Button(action: {
                    model.counter1 += 1
                    print(model.counter1)
                }, label: {
                    Text("Press to increase (\(model.counter1))")
                })
                PushView(destination: SecondView(model : model), label: {
                    Text("Go to 2nd view")
                })
            }
        }
    }
}

When press the "Press to increase" button in the second view, the app pop to the root view immediately
Runs on Xcode 12.2 & iOS simulator iPhone 12 Pro, iOS 14.2

Transition not applied to entire View

When I use a PushView, part of the contents of the View are not treated the same for the transition. They will transition instantly, while the rest of the content transitions normally. It seems to primarily affect "dynamic" content, such as a ForEach. Is there a way around this?

NavigationStack stops functioning once I open a fullScreenCover

I have this chat tab on my app which uses a fullScreenCover. The problem is, after I open that fullScreenCover, all the Push functions of the navigationStack stop working. They animate but done push to anything, its like it is sliding itself on top of it.

How to manually make view .root

I have this app where I use userDefaults to store if the user was previously logged in. If they weren't previousy logged in, the first view is a login page. If they were previously logged in, the first view is a different view. That said, I want to implement a logout feature. But if they were already logged in, and the first view is not the login page, how can I pop back to a view that never appeared ie (the login page).

@ObservedObject var viewModel: ViewModel

you have mentioned programmatic push/pop in the examples, but it's not clear how you implemented the ObservedObject var viewModel: ViewModel, and what it's purpose is, and what function performBackgroundActivities() is doing, would it be same if you just called DispatchQueue.main.async { self.navigationStack.push(ChildView()) } inside button's action?, can you explain this more? or do we have to implement ViewModel logic ourselves

struct MyHome: View {
    @ObservedObject var viewModel: ViewModel
    @EnvironmentObject private var navigationStack: NavigationStack

    var body: some View {
        Button(action: {
            self.viewModel.performBackgroundActivities(withCallback: {
                DispatchQueue.main.async {
                    self.navigationStack.push(ChildView())
                }
            })
        }, label: {
            Text("START BG ACTIVITY")
        })
    }
}

@State variables get reset after pop

Using a standard NavigationView and NavigationLink, the @State variables retain their values when pushed and subsequently popped back into view. iOS example:

import SwiftUI


struct ContentView: View {
    var body: some View {
        NavigationView {
            AAA()
        }
    }
}

struct AAA: View {
    @State var text = "default text"
    var body: some View {
        VStack {
            TextEditor(text: $text)
            NavigationLink(destination: BBB()) {
                Text("Push")
            }
        }
    }
}

struct BBB: View {
    var body: some View {
        Text("BBB")
    }
}

Edit the text, click Push, then go Back. The texteditor retains the changes that were made before pushing.

I tried the same thing with StackNavigationView and find that my @State variable is reset after a pop.

iOS example:

import SwiftUI
import NavigationStack

struct ContentView: View {
    var body: some View {
        NavigationStackView {
            AAA().padding()
        }
    }
}

struct AAA : View {
    @State private var data = "default text"

    var body: some View {
        VStack {
            TextEditor(text: $data)
            PushView(destination: BBB()) {
                Text("Push")
            }
        }
    }
}

struct BBB : View {
    var body: some View {
        PopView {
            Text("Pop")
        }
    }
}

If you edit text the editor, hit Push, then Pop back you see the text has been reset to its default state.

Is this expected behavior?

Toolbar integration

Hello.
Thanks for this amazing work. Could you please suggest how to integrate NavigationStackView with .toolbar { }. Currently I have two ideas:

  1. Add .toolbar {} to the NavigationStackView {}. In this case it is not clear how to switch between views forth and back. Each time the user presses a toolbar button a new instance of the view will be added instead of pop/push combination
  2. Do not mix .toolbar {} with NavigationStackView {}. At the top level we might have NavigationView.toolbar {} to switch between high level views. For the deeper navigation levels use NavigationStackView. In this case some of the original issue addressed by NavigationStackView might return back.

Also I tried to push view from the toolbar block which leads to the following issue: Fatal error: No ObservableObject of type NavigationStack found. A View.environmentObject(_:) for NavigationStack may be missing as an ancestor of this view.: file SwiftUI, line 0. It happens because NavigationStack is available only inside NavigationStackView:

struct HomeView: View {
    @EnvironmentObject private var navigationStack: NavigationStack
    var body: some View {
        NavigationStackView {
            AppScreen {
                VStack {
                    Text("Home screen")
                }
            }
        }
        .toolbar {
            ToolbarItemGroup(placement: .bottomBar) {
                Button("Home") {
                    self.navigationStack.push(HomeView())
                }
                Button("Settings") {
                    self.navigationStack.push(SettingsView())
                }
            }
        }
    }
}

If I place it next to the AppScreen then a toolbar will gone when the next view is pushed.

What thoughts do you have on this subject?

Support for iOS 15.

This is not working in iOS 15 and also breaks things. Breaks formatting in some subViews, colors, etc. Also, some buttons not working, I have tested buttons initiating bluetooth scan action. Could be interoperability with CoreBluetooth.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.