How to add TabView/anything under NavigationView? - swift

I have this code to display NavigationView with toolbar, searchable:
var body: some View {
NavigationView {
TabView(selection: $selectedIndex) {
...
}
.tabViewStyle(.page(indexDisplayMode: .never))
.toolbar {
...
}
.searchable(text: $searchText)
}
}
I want to achieve a result with tabs similar to this:
However, I can't add anything except searchable and toolbar to the NavigationView.
I tried to make it with NavigationStack instead, TabView, and all ToolbarItemGroup placements - but no luck.
Please help, thank you.

Related

SWIFTUI: NavigationStack breaks what NavigationView was doing correctly. What's the best solution?

In one of the projects I decided to comply with apple and get rid of NavigationView.
In the project you had a list of buildings and after choosing a Building you had several tabs with bills, documents etc. Each of the Tabs was a different view, each with its own toolbar, buttons and functions. Here's the sample code:
import SwiftUI
struct TestView: View {
var testData: [Building] = [
Building(name: "Crystal Balls"),
Building(name: "Geneva Towers"),
Building(name: "Villa Navagero"),
]
var body: some View {
//Here's the problem... If I change it to NavigationStack
//all the of toolbars in tabs are gone
NavigationView {
List(testData) {test in
NavigationLink {
TabView {
NavigationStack{
Text(test.name)
.navigationTitle("My Bills")
.navigationBarTitleDisplayMode(.inline)
.toolbar{
ToolbarItem{
Button{} label: {
Image(systemName: "gear.circle")
}
}
ToolbarItem{
Button{} label: {
Image(systemName: "plus.circle")
}
}
}
}
.tabItem{
Label("Bills", systemImage: "doc.fill.badge.ellipsis")
}
Text(test.name)
.tabItem{
Label("Skills", systemImage: "doc.fill")
}
}
} label: {
Text(test.name)
}
}
}
}
}
struct TestView_Previews: PreviewProvider {
static var previews: some View {
TestView()
}
}
Having every tab as a different view and having a back button is too convenient, getting all the toolbar button to the TabView seems to "dirty" and inefficient.
Maybe somebody has figured out a solution?

How come my NavigationLink won't work when clicked?

I am trying to make it so that when I click the icon, the "scoreView()" is opened. When I click it, nothing works right now. Here is the code:
HStack {
Image(systemName: "arrow.counterclockwise")
NavigationLink(destination: scoreView(scoreTracker: $scoreTracker)) {
Spacer()
Image(systemName: "list.bullet")
}
}
Does it have something to do with the fact that I don't have a navigationView? I'm new to this and experimenting so I'm not very clear on it.
EDIT:
I have added a NavigationView, yet the NavigationLink covers half the screen, and when clicked, the view is only changed in that square.
Before clicking the NavigationLink
After clicking the NavigationLink
HStack {
Image(systemName: "arrow.counterclockwise")
NavigationView {
NavigationLink(destination: scoreView(scoreTracker: $scoreTracker)) {
Image(systemName: "list.bullet")
}
}
}
Does it have something to do with the fact that I don't have a navigationView?
Yes. According to the documentation:
Users click or tap a navigation link to present a view inside a NavigationView.
It will only work inside a NavigationView. If you're not using one, consider sheet or fullScreenCover instead. Or, make your own overlay with a ZStack.
Example NavigationView usage:
struct ContentView: View {
var body: some View {
NavigationView { /// directly inside `var body: some View`
VStack { /// if you have multiple views, make sure to put them in a `VStack` or similar
Text("Some text")
/// `ScoreView` should be capitalized
NavigationLink(destination: ScoreView(scoreTracker: $scoreTracker)) {
Image(systemName: "list.bullet")
}
}
}
}
}

NavigationView height irregular swiftui

I have a NavigationView and added a title. The problem is it looks weird when I run it.
var body: some View {
NavigationView {
Form {
Section {
Text("Hello World")
}
}
.navigationBarTitle("SwiftUI", displayMode: .inline)
}
}
The image looks weird. How can I make the navigation height look better just like UIKIt Navigation Bar
You have a double-nested NavigationView.
The view that you are showing in your example is already being presented from a NavigationView, so you don't need to create an additional view.
This is because the navigation view context is preserved when you use a NavigationLink.
Try removing it:
var body: some View {
Form {
Section {
Text("Hello World")
}
}
.navigationBarTitle("SwiftUI", displayMode: .inline)
}

NavigationView inside a TabView Swift UI

I'm just picking up SwiftUI after a long break but I don't understand why I can't place a Navigation View within a Tab View.
I want my Navigation View to be a .tabItem so the view appears as part of the main app navigation so I'm trying this :
struct ContentView: View {
var body: some View {
TabView {
NavigationView {
.tabItem {
Text("Home")
}
Text("Tab bar test")
.navigationBarTitle("Page One")
}
}
This doesn't work with error message
Cannot infer contextual base in reference to member 'tabItem'
But when I try this
var body: some View {
TabView {
NavigationView {
Text("Tab bar test")
.navigationBarTitle("Page One")
}
}
.tabItem {
Image(systemName: "1.circle")
Text("Home")
}
}
It builds fine but the tab bar doesn't show up.
My primary question which I'm hoping would be useful to others, is ...
Why can't I make a make a Navigation View a tab bar item by nesting .tabItem directly inside the Navigation View (as per my first example)?
I think it's a similar question to this one but there's no code there. And then quite similar to this one but they seem to be using .tabItem directy with ContentView like I want to with NavigationView but that isn't building!?
I'm probably misunderstanding something simple but I don't get this at all at the moment.
Do this for a better overview:
ContentView:
struct ContentView : View {
var body: some View {
TabView {
FirstView()
.tabItem {
Image(systemName: "folder.fill")
Text("Home")
}
SecondView()
.tabItem {
Image(systemName: "folder.fill")
Text("SecondView")
}
}
}
}
FirstView
struct FirstView: View {
var body: some View {
NavigationView {
Text("FirstView")
.navigationBarTitle("Home")
}
}
}
}
SecondView
struct SecondView: View {
var body: some View {
NavigationView {
Text("SecondView")
.navigationBarTitle("Home")
}
}
}
}
.tabItem should be used as a modifier on the view that represents that tab.
In the first example, this doesn't work because of a syntax error -- you're trying to use it on the opening of a closure in NavigationView {, when instead you want it on the outside of the closing brace: NavigationView { }.tabItem(...)
In the second example, you're using .tabItem as a modifier on the entire TabView instead of the NavigationView.
Both of your examples may have revealed what was going on more obviously if you indent your code so that you can see the hierarchy. Trying selecting your code in Xcode and using Ctrl-I to get Xcode to properly format it for you.
Here's a working version:
struct ContentView : View {
var body: some View {
TabView {
NavigationView {
Text("Tab bar test")
.navigationBarTitle("Page One")
}
.tabItem { //note how this is modifying `NavigationView`
Image(systemName: "1.circle")
Text("Home")
}
}
}
}

SwiftUI: How to remove caret right in NavigationLink which is inside a List

I have a issue about NavigationLink in SwiftUI. I have a List restaurant and have NavigationLink in it. I tried to remove the caret right in right of NavigationLink section but not success
I tried to remove caret using buttonStyle but is's not work.
List(vm.restaurants) { (restaurant: Restaurant) in
NavigationLink(destination: ResDetailView(restaurant: restaurant)) {
RestaurantRow(life: life)
}.buttonStyle(PlainButtonStyle())
}
Chris' answer works, but EmptyView has a height which adds empty space to the bottom of the cell. Instead, you can use ZStack to make the navigation link on top of the cell.
List {
ForEach(0..<items.count) { i in
ZStack {
ContactRow(item: self.items[i])
NavigationLink(destination: ChatView()) {
EmptyView()
}
}
}
}
you can do it like this:
var body: some View {
NavigationView() {
List(menu, id: \.self) { section in
VStack{
Text(section.name)
NavigationLink(destination: Dest()) {
EmptyView()
}
}
}
}
The easiest way to get rid of the disclosure indicator is to set the padding on the NaviagtionLink:
NavigationView {
List {
ForEach(items) { item in
NavigationLink(destination: Destination(item: item)) {
CustomCell(item: item)
} .padding([.trailing], -30.0)
}
}
}
I wouldn't recommend it though - it's a way of showing your users that there is more data available if the tap on one of the cells.