NavigationView nests TabView, I have a List, and push to the next page
When the application returns to the background and returns to the active state, the push page automatically pops up.
If TabView nests NavigationView, there will be no problem, but I want NavigationView to nest TabView, is there any way to solve it
struct ContentView: View {
var body: some View {
NavigationView {
TabView {
List {
ForEach(0..<30) { index in
RowView(index: index)
}
}
}
}
}
}
struct RowView: View {
var index: Int
#State var userViewActive: Int?
var body: some View {
NavigationLink {
Text("Hello, world!")
} label: {
Text("Hello, world!")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
In a tabview each tab should manage its own view state. Aka
Every tab should have it's own navigation view. If you add this, you will see that your problem is solved.
Related
I am building a macOS SwiftUI app in which I need to perform navigation from my View A to View B. Here is a small screenshot.
Here is my implementation:
struct ViewA: View {
var body: some View {
VStack {
Text("VIEW A")
Button("Go to View B") {
// I want to go to View B and also pass some data to View B
}
}
}
}
struct ViewB: View {
let data: String
var body: some View {
VStack {
Text("VIEW B")
}
}
}
struct ContentView: View {
#EnvironmentObject var appState: AppState
var body: some View {
NavigationView {
SideBar()
ViewA()
}
}
}
In iOS I would use NavigationLink, but for macOS apps NavigationLink is not working as expected. Any ideas?
I have discovered a regression in watchOS 8.1RC with NavigationLink triggered from a TabView.
It's immediately dismissed.
It was working in watchOS 8.0 or in Simulator (watchOS 8.0).
Do you know a workaround ?
Thanks
Sample code:
import SwiftUI
#main
struct TestNavigationApp: App {
var body: some Scene {
WindowGroup {
NavigationView {
ContentView()
}
}
}
}
struct ContentView: View {
var body: some View {
List {
NavigationLink(destination: ContentView1()) {
Text("To TabView")
}
}
}
}
struct ContentView1: View {
var body: some View {
TabView {
NavigationView {
NavigationLink(destination: ContentView2()) {
Text("To ContentView2")
}
}
VStack {
Text("Screen2")
}
}
}
}
struct ContentView2: View {
var body: some View {
Text("ContentView2")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I'm experiencing the same issue with watchOS 8.1 (and 8.3 beta) while it was working with previous watchOS versions.
We were able to get it working again by moving the NavigationView inside the TabView. This workaround isn't ideal at all but it does seem to work.
#State private var tabSelection = 1
var body: some Scene {
WindowGroup {
TabView(selection: $tabSelection) {
NavigationView {
// List goes here
}
.tag(1)
VStack(alignment: .center, spacing: 12, content: {
// content 2nd tab: we didn't have a list in the 2nd tab
})
.tag(2)
}
}
}
However, there are 2 things impacted with this fix:
I didn't get the navigationBarTitle working, so there won't be a title on top of the screen.
If you click on an item in the list, it will navigate to your page (as expected) but the TabView dots at the bottom of the screen will remain.
This question already has an answer here:
SwiftUI iOS14 - NavigationView + List - Won't fill space
(1 answer)
Closed 2 years ago.
If I wrap a VStack with a List inside a NavigationView, the resulting list is indented, see image. This is not the expected formatting because I'd want the list to cover the whole screen width.
How can I fix this and why does this happen?
Note: This indentation behavior would go away if I remove the VStack, but here I do want to include the Text box ("Something...") inside the NavigationView, because I want it to go away once a user clicks on an item.
Full code below, Xcode 12.3:
import SwiftUI
struct ListView: View {
var items: [String]
var body :some View {
List {
ForEach(items, id: \.self) { item in
NavigationLink(destination: Text(item)){
Text(item)
}
}
}
}
}
struct ContentView: View {
var body: some View {
NavigationView{
VStack{
Text("Something that should disappear when I click on the item")
ListView(items: ["a", "b"])
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Hey all you need to do is add the modifier for a .liststyle
.listStyle(InsetListStyle())
Also you should be aware that there is no way to remove the chevron symbol on lists
import SwiftUI
struct ListView: View {
var items: [String]
var body :some View {
List {
ForEach(items, id: \.self) { item in
NavigationLink(destination: Text(item)){
Text(item)
}
}
}.listStyle(InsetListStyle())
}
}
struct ContentView: View {
var body: some View {
NavigationView{
VStack{
Text("Something that should disappear when I click on the item")
ListView(items: ["a", "b"])
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
When I push more than one view, multiple back buttons are visible in the navigation bar.
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination:SecView()) {
Text("Primo")
}
}
}
}
struct SecView: View {
var body: some View {
NavigationView {
NavigationLink(destination:TerView()) {
Text("Secondo")
}
}
}
}
struct TerView: View {
var body: some View {
Text("Hello World!")
}
}
I would like to have only one back button per view.
Here is a screenshot of the problem.
There should only be a single NavigationView at the root of your navigation stack.
Remove the NavigationView block from SecView and you will then have a single navigation bar owned by ContentView.
as Gene said, there should only be a single NavigationView at the root of you navigation stack. This means that the next time you need to navigate to a page in a different View, you will add a NavigationLink but not wrap it in a NavigationView. So in the code that you initially posted, you need to remove the NavigationView from your SecView View but still keep the NavigationLink. See the code below:
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination:SecView()) {
Text("Primo")
}
}
}
}
struct SecView: View {
var body: some View {
NavigationLink(destination:TerView()) {
Text("Secondo")
}
}
}
struct TerView: View {
var body: some View {
Text("Hello World!")
}
}
Given this simple NavigationView:
struct ContentView : View {
var body: some View {
NavigationView {
VStack {
NavigationLink("Push Me", destination: Text("PUSHED VIEW"))
}
}
}
}
Did anyone find a way of disabling the NavigationView animation when a destination view is pushed/popped into/from the stack?
This has been possible in UIKit since iOS2.0! I think it is not too much to ask from the framework. I tried all sorts of modifiers on all views (i.e., the NavigationView container, the destination view, the NavigationLink, etc)
These are some of the modifiers I tried:
.animation(nil)
.transition(.identity)
.transaction { t in t.disablesAnimations = true }
.transaction { t in t.animation = nil }
None made a difference. I did not find anything useful in the EnvironmentValues either :-(
Am I missing something very obvious, or is the functionality just not there yet?
Xcode 11.3:
Right now there is no modifier to disable NavigationView animations.
You can use your struct init() to disable animations, as below:
struct ContentView : View {
init(){
UINavigationBar.setAnimationsEnabled(false)
}
var body: some View {
NavigationView {
VStack {
NavigationLink("Push Me", destination: Text("PUSHED VIEW"))
}
}
}
}
First you need state for the NavigationLink to respond to, then set that state inside a transaction with animations disabled, as follows:
struct ContentView : View {
#State var isActive = false
var body: some View {
NavigationView {
VStack {
NavigationLink(isActive: $isActive, destination: {
Text("PUSHED VIEW")}) {
Text("Push Me")
}
Button("Navigate Without Animation") {
var transaction = Transaction()
transaction.disablesAnimations = true
withTransaction(transaction) {
isActive = true
}
}
}
}
}
}
I recently created an open source project called swiftui-navigation-stack (https://github.com/biobeats/swiftui-navigation-stack) that contains the NavigationStackView, a view that mimics the navigation behaviours of the standard NavigationView adding some useful features. For example, you could use the NavigationStackView and disable the transition animations as requested by Kontiki in the question. When you create the NavigationStackView just specify .none as transitionType:
struct ContentView : View {
var body: some View {
NavigationStackView(transitionType: .none) {
ZStack {
Color.yellow.edgesIgnoringSafeArea(.all)
PushView(destination: View2()) {
Text("PUSH")
}
}
}
}
}
struct View2: View {
var body: some View {
ZStack {
Color.green.edgesIgnoringSafeArea(.all)
PopView {
Text("POP")
}
}
}
}
PushView and PopView are two views that allow you push and pop views (similar to the SwiftUI NavigationLink). Here is the complete example:
import SwiftUI
import NavigationStack
struct ContentView : View {
var body: some View {
NavigationStackView(transitionType: .none) {
ZStack {
Color.yellow.edgesIgnoringSafeArea(.all)
PushView(destination: View2()) {
Text("PUSH")
}
}
}
}
}
struct View2: View {
var body: some View {
ZStack {
Color.green.edgesIgnoringSafeArea(.all)
PopView {
Text("POP")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
The result is:
It would be great if you guys joined me in improving this open source project.