SwiftUI TabBar: Action for tapping TabItem of currently selected Tab to reset view - swift

The app I am working on is based around a TabBar, and when I am on a tab I want to be able to click the tabItem again to reset the view, similar to how Twitter does it in their tabBar.
I do not know how to recognize that action though. Adding a button to the TabItem is not working, addidng a tapGesture modifier isn't either, and I can't think of anything else I could try.
struct ContentView: View {
var body: some View {
TabView() {
Text("Tab 1")
.tabItem {
Image(systemName: "star")
.onTapGesture {
print("Hello!")
}
Text("One")
}
.tag(0)
Text("Tab 2")
.tabItem {
Button(action: {
print("Hello!")
}, label: {
Image(systemName: "star.fill")
})
}
.tag(1)
}
}
}
It should't automatically reset when opening the tab again, which I have seen discussed elsewhere, but when tapping the tabItem again.
What other things am I possibly missing here?

Here is possible solution - inject proxy binding around TabView selection state and handle repeated tab tapped before bound value set, like below.
Tested with Xcode 12.1 / iOS 14.1
struct ContentView: View {
#State private var selection = 0
var handler: Binding<Int> { Binding(
get: { self.selection },
set: {
if $0 == self.selection {
print("Reset here!!")
}
self.selection = $0
}
)}
var body: some View {
TabView(selection: handler) {
Text("Tab 1")
.tabItem {
Image(systemName: "star")
Text("One")
}
.tag(0)
Text("Tab 2")
.tabItem {
Image(systemName: "star.fill")
}
.tag(1)
}
}
}

Related

SwiftUI: Problems with List inside TabViews inside NavigationView

I want to place a TabView inside a NavigationView with different titles depending on the selected tab. Inside those tabs I want to place a List view. See the code below:
struct ContentView: View {
#State private var selection = 1
var body: some View {
TabView(selection:$selection) {
Page_1()
.tabItem {
Image(systemName: "book")
Text("Page 1")
}
.tag(1)
Page_2()
.tabItem {
Image(systemName: "calendar")
Text("Page 2")
}
.tag(2)
}
}
}
struct Page_1: View {
#State var selectedTab = "1"
var body: some View {
NavigationView {
TabView(selection: $selectedTab) {
List {
ForEach(0..<20){i in
Text("Test")
}
}
.tag("1")
.navigationBarTitle("Page 1 Tab 1")
List {
ForEach(0..<20){i in
Text("Test")
}
}
.tag("2")
.navigationBarTitle("Page 1 Tab 2")
}
.tabViewStyle(.page(indexDisplayMode: .never))
.ignoresSafeArea(.all)
.background()
}
}
}
struct Page_2: View {
#State var selectedTab = "1"
var body: some View {
NavigationView {
TabView(selection: $selectedTab) {
List {
ForEach(0..<20){i in
Text("Test")
}
}
.tag("1")
.navigationBarTitle("Page 2 Tab 1")
List {
ForEach(0..<20){i in
Text("Test")
}
}
.tag("2")
.navigationBarTitle("Page 2 Tab 2")
}
.tabViewStyle(.page)
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
.ignoresSafeArea()
.background()
}
}
}
The problem is that when the Pages first appear the lists inside their TabViews seem to be placed slightly too low and then move up. You can see this especially when you switch tabs like here:
After switching back and forth between the tabs they are placed correctly until I freshly start the app again. Would really appreciate your help!:)
Edit
As suggested I tried to put the NavigationViews inside the TabView. That solves the problem with the wrong positioning. However, it leads to the views not being shown at all before I switch back and forth between them. You can see what that looks like in the picture below:

SwiftUI: Tabview Repeating itself

I'm trying to create a tabview for a macOS 10.15 app.
TabView {
BookmarksView()
.tabItem {
Text("Bookmark Settings")
}
DisplaySettings()
.tabItem {
Text("Display Settings")
}
}
And in any of my views included in the tab that has one element in the body it renders properly in the tab view.
struct BookmarksView: View {
var body: some View {
Text("Bookmarks View")
.font(.title)
.font(Font.body.bold())
}
}
But if i add any other element in the view, the tab repeats and shows the added element in its own tab.
struct BookmarksView: View {
var body: some View {
Text("Bookmarks View")
.font(.title)
.font(Font.body.bold())
Text("Testing")
.font(.system(size: 15))
}
}
Try to wrap them in container (stack or something) explicitly, like
struct BookmarksView: View {
var body: some View {
VStack { // << this !!
Text("Bookmarks View")
.font(.title)
.font(Font.body.bold())
Text("Testing")
.font(.system(size: 15))
}
}
}

Swiftui invisible bar on the top of the screen

I have the following in problem.
If I try to give a view a color (Color.red for example)
I get the following output:
I can just add .edgesignoressafearea(.top) and the top also gets red. But when I want to add an clickable item, the user won't be able to click it since there still is this invisible bar on the top of the screen. Does Anyone know what my problem is? The problem is in all the tabable views(Timeline, Favorits, Discover, Account). So It must be in either the first code or in tabview (second code) that I send in this post.
When the user clicks on the app first they get this view sending the user to the signin view or the app itself:
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: tabView().navigationBarHidden(true), isActive: $tabview, label: { EmptyView() })
NavigationLink(destination: loginView().navigationBarHidden(true), isActive: $login, label: { EmptyView() })
if tabview == false && login == false {
Text("loading")
.onAppear(perform: checklogin)
}
}
.navigationBarBackButtonHidden(true)
.navigationBarHidden(true)
}
}
Then the apps sends them to tabview:
var body: some View {
TabView(selection: $selection) {
Timeline()
.tabItem {
Label("timeline", systemImage: "house")
}
.tag(0)
Favorits()
.tabItem {
Label("favorits", systemImage: "heart")
}
.tag(1)
Discover()
.tabItem {
Label("discover", systemImage: "network")
}
.tag(2)
Account()
.tabItem {
Label("account", systemImage: "person")
}
.tag(3)
}
.navigationBarBackButtonHidden(true)
.navigationBarHidden(true)
}
The problem happens on all of this views.
This is the view where I made the screenshot of:
var body: some View {
ZStack {
Color.red
Text("Hello fav!")
}
.navigationBarBackButtonHidden(true)
.navigationBarHidden(true)
}
add .edgesIgnoringSafeArea(.top) and remove your navigation bar if you don't want to be able to get back to your login view anytime.
That's the full code with a login page, now it depends what you want on that login page :
import SwiftUI
struct ContentView: View {
#State var showLoginView: Bool = false
var body: some View {
VStack {
if showLoginView {
MainView()
} else {
Button("Login") {
self.showLoginView = true
}
}
}
}
}
struct MainView: View {
var body: some View {
TabView {
TimeLine()
.tabItem {
Label("timeline", systemImage: "house")
}
Favorits()
.tabItem {
Label("favorits", systemImage: "heart")
}
Discover()
.tabItem {
Label("discover", systemImage: "network")
}
Account()
.tabItem {
Label("account", systemImage: "person")
}
}
}
}
struct TimeLine: View {
var body: some View {
Color.blue
.edgesIgnoringSafeArea(.top)
}
}
struct Favorits: View {
var body: some View {
ZStack {
Color.red
.edgesIgnoringSafeArea(.top)
Text("Hello fav!")
}
}
}
struct Discover: View {
var body: some View {
Color.yellow
.edgesIgnoringSafeArea(.top)
}
}
struct Account: View {
var body: some View {
Color.purple
.edgesIgnoringSafeArea(.top)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
You need to set the navigation Title to "" because your View is embedded in NavigationView
Create a ViewModifier like this and apply it to your VStack
struct HiddenNavBarModifier: ViewModifier {
func body(content: Content) -> some View {
content
.navigationBarTitle("", displayMode: .inline)
.navigationBarHidden(true)
}
}

TabView doesn't show text on first view SwiftUI

The problem: When I lunch the app, the first tabview doesn't display the name below. I have to go to another view and come back for it to show. Why?
struct MotherView : View {
var body: some View {
VStack {
if viewRouter.currentPage == "onboardingView" {
OnboardingView()
} else if viewRouter.currentPage == "homeView" {
TabView {
HomeView()
.tabItem {
Image(systemName: "house")
Text("Menu")
}
SettingsView()
.tabItem {
Image(systemName: "slider.horizontal.3")
Text("Order")
}
}
}
}
}
}
We can just guess, because you didn't show us the code of your HomeView.
Nevertheless I guess in your HomeView you have this line .navigationBarTitle("", displayMode: .inline).
Remove it and it will work as expected.

How to create an UItoolbar in SwiftUI with Xcode 11.2

I don't know how to create an UIToolbar at the bottom of the screen in SwiftUI.
There is no controller in SwiftUI but you can add like this.
var body: some View {
NavigationView {
VStack {
List(model.items) { item in
ItemViewRow(item: item)
}
HStack {
Button(action: {
}) {
Image(systemName: "someimage")
}
Spacer()
Button(action: {
}) {
Image(systemName: "someimage")
}
}.padding()
}
.navigationBarTitle(Text("Items"))
}
}