SwiftUI how to refresh one single tabview without switching tabbar - swiftui

I need do some refresh on some view after networking request completion, but my tab bar auto switched to first tabview after refreshing the page, here is my code:
//tab view
struct PricesView: View {
#ObservedObject var netWorkManager = NetworkManager.shareInstance
var body: some View {
if netWorkManager.dataList.isEmpty {
LoadingView().onAppear(perform: netWorkManager.fetchPricesData)
} else {
Text("Prices").foregroundColor(.red)
}
}
}
...
//main view
struct ContentView: View {
var body: some View {
TabView {
HomeView().tabItem {
Image(systemName: "house.fill")
Text("home")
}
AlertsView().tabItem {
Image(systemName: "flag.fill")
Text("alerts")
}
LinksView().tabItem {
Image(systemName: "link.icloud")
Text("link")
}
PricesView().tabItem {
Image(systemName: "bitcoinsign.circle")
Text("prices")
}
}
}
}
how can I avoid this?

Use selection and tag.
struct ContentView: View {
#State var selection = 0 // <- Here declare selection
var body: some View {
TabView(selection: $selection) { // <- Use selection here
HomeView().tabItem {
Image(systemName: "house.fill")
Text("home")
}.tag(0) // <- Add tag
AlertsView().tabItem {
Image(systemName: "flag.fill")
Text("alerts")
}.tag(1) // <- Add tag
LinksView().tabItem {
Image(systemName: "link.icloud")
Text("link")
}.tag(2) // <- Add tag
PricesView().tabItem {
Image(systemName: "bitcoinsign.circle")
Text("prices")
}.tag(3) // <- Add tag
}
}
}

Related

SwiftUI TabView repeats first entry

Xcode RC 14.1
The first tab is generated twice. The first one works, the second brings up a blank screen. This has been reported elsewhere on SO and people suggest removing Spacer()s but this made no difference.
The code below has two variants, one with a enum for the tag as opposed to an integer but they both misbehave identically. (Not sure why all the code hasn't ended up grey below?)
import SwiftUI
struct MenuView: View {
private enum Tab: Hashable {
case location
case calculate
case install
case results
case about
}
// #State private var tabBarSelected: Tab = .location
#State private var selectedTab = 0
var body: some View {
VStack {
TabView(selection: $selectedTab) {
LocationView()
// .tag(Tab.location)
.tag(0)
.tabItem {
Text("Location")
Image(systemName: "globe.europe.africa")
}
CalculateView()
// .tag(Tab.calculate)
.tag(1)
.tabItem {
Text("Calculate")
Image(systemName: "apps.ipad")
}
InstallView()
// .tag(Tab.install)
.tag(2)
.tabItem {
Text("Install")
Image(systemName: "window.ceiling.closed")
}
ResultsView()
.tag(3)
// .tag(Tab.results)
.tabItem {
Text("Results")
Image(systemName: "sun.max.fill")
}
AboutView()
.tag(4)
// .tag(Tab.about)
.tabItem {
Text("About")
Image(systemName: "gear")
}
} // TabView
.accentColor(.yellow) //Active tab color
} // VStack
} // body
init() {
UITabBar.appearance().barTintColor = UIColor.systemGray //TabBar color
UITabBar.appearance().unselectedItemTintColor = UIColor.systemGray2
UITabBar.appearance().isOpaque = false
}
}
struct MenuView_Previews: PreviewProvider {
static var previews: some View {
MenuView()
}
}
You need to wrap your content in a VStack, kindly check your code in LocationView().
Instead of this:
var body: some View {
Text("Hi")
Text("welcome")
}
Use the code below:
var body: some View {
VStack {
Text("Hi")
Text("welcome")
}
}

How to hide TabView navigating from tabItem in childview in SwiftUI?

I am using TabView in swiftui. I want navigate child view from tabview tabItem. When I navigate from taview to childview, it shows tabview in bottom. Here is the image.. that click login goes to Myview page. But in Myview, Tabview is not hiding
Here is my code..
Tabview
struct WelcomeView: View {
var body: some View {
TabView {
HomeView()
.tabItem {
Image("home_icon")
Text("Home")
}
.tag(0)
NotificationView()
.tabItem {
Image("notification_icon")
Text("Notification")
}.tag(1)
AccountView()
.tabItem {
Image("account_icon")
Text("Account")
}.tag(2)
SettingView()
.tabItem {
Image("settings_icon")
Text("Setting")
}.tag(3)
}
}
}
In SettingView tabItem:
struct SettingView: View {
#State private var isActive = false
var body: some View {
NavigationView {
VStack(alignment: .leading) {
VStack {
Button(action: {
isActive = true
}) {
Text("Login")
}
NavigationLink("", destination: MyView(), isActive: $isActive)
}
}
}
}
}
MyView:
struct MyView: View {
var body: some View {
ZStack{
Text("Hello My View")
}.navigationBarHidden(true)
.navigationBarTitleDisplayMode(.inline)
}
}
When I click login Button in SettingView tabItem, It goes to MyView page. But in MyView page tabview is not hide.
How to hide tabview from MyView page?
To hide the tab we can add a Bool that will take care of showing the view or not. Then by using #Binding we can pass it to the other child views, whatever changes you make down the chain will affect all the views.
struct WelcomeView: View {
#State var isTabViewShown = true
var body: some View {
TabView {
if isTabViewShown {
HomeView()
.tabItem {
Image(systemName: "house.fill")
Text("Home")
}
.tag(0)
NotificationView()
.tabItem {
Image(systemName: "envelope.open.fill")
Text("Notification")
}.tag(1)
AccountView()
.tabItem {
Image(systemName: "person.crop.circle")
Text("Account")
}.tag(2)
SettingView(isTabViewShown: $isTabViewShown)
.tabItem {
Image(systemName: "gearshape")
Text("Setting")
}.tag(3)
}
}
}
}
struct MyView: View {
#Binding var isTabViewShown: Bool
var body: some View {
ZStack{
Text("Hello My View")
}
.navigationBarHidden(false)
.navigationBarTitleDisplayMode(.inline)
.onAppear {
isTabViewShown = false
}
}
}
struct SettingView: View {
#State private var isActive = false
#Binding var isTabViewShown: Bool
var body: some View {
NavigationView {
VStack(alignment: .leading) {
VStack {
Button(action: {
isActive = true
}) {
Text("Login")
}
NavigationLink("", destination: MyView(isTabViewShown: $isTabViewShown), isActive: $isActive)
//Here is a button if you want to show it again
Button(action: {
isTabViewShown.toggle()
//You can also use this is you don't want to use a toggle
// isTabViewShown = true
}) {
Text("Show again")
}
}
}
}
}
}
struct HomeView: View {
var body: some View {
Text("Home View")
}
}
struct NotificationView: View {
var body: some View {
Text("Notification View")
}
}
struct AccountView: View {
var body: some View {
Text("Account View")
}
}

SwiftUI problem with not reloading Tab Item when using NavigationLink

I'm using Navigation View inside TabView and the problem is that if I an on Tab A and with NavigationView I open other Views, when changing from tab A to B and after a while I came back to tab A I dosen't reload tab A from beginning but it show the last View open with NavitagionLink. The problem is that in each View I'm getting data from a DB and because of that if shows an empty view.
My ContentView looks like this:
struct ContentView: View {
#ObservedObject var appState = AppState()
#State var currentTab : Tab
var body: some View {
TabView(selection: $appState.currentTab) {
NavigationView {
HomeView(appState: appState)
}
.tabItem {
if appState.currentTab == .home {
Image(systemName: "house.fill")
} else {
Image(systemName: "house")
}
Text(LocalizedStringKey("HomeTabMenu"))
}.tag(Tab.home)
NavigationView {
SearchView()
}
.tabItem {
if appState.currentTab == .search {
Image(systemName: "magnifyingglass.circle.fill")
} else {
Image(systemName: "magnifyingglass")
}
Text(LocalizedStringKey("SearchTabMenu"))
}.tag(Tab.search)
NavigationView {
AddItemView(appState: appState)
}
.tabItem {
if appState.currentTab == .add {
Image(systemName: "plus.circle.fill")
} else {
Image(systemName: "plus.circle")
}
Text(LocalizedStringKey("SellTabMenu"))
}.tag(Tab.add)
NavigationView {
ShoppingCartFavoritesView()
}
.tabItem {
if appState.currentTab == .favorites {
Image(systemName: "cart.fill")
} else {
Image(systemName: "cart")
}
Text(LocalizedStringKey("CartTabMenu"))
}.tag(Tab.favorites)
NavigationView {
ProfileView(appState: appState)
}
.tabItem {
if appState.currentTab == .profile {
Image(systemName: "person.fill")
} else {
Image(systemName: "person")
}
Text(LocalizedStringKey("ProfileTabMenu"))
}.tag(Tab.profile)
}//End TabView
.accentColor(Color("ColorMainDark"))
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(currentTab: Tab.home)
}
}
class AppState: ObservableObject {
#Published var currentTab : Tab = .home
}
enum Tab {
case home, search, add, favorites, profile
}
And if I open SearchView()
struct SearchView: View {
var body: some View {
NavigationLink(destination: View_2(id: "ABC")){
Text("ABC")
}
}
}
struct View_2: View {
#ObservedObject var performSearchProducts = PerformSearchInProducts()
var id : String
var body: some View {
ScollView {
ForEach(performSearchProducts.products) { product in
Text(product.name)
}
}.onAppear(perform: {
self.performSearchProducts.searchSubCategory(id: id)
})
}
}
If in SearchView I'm on View_2() and the I open another Tab, when I come back to tab SearchView it doesn't show the SearchView(), but it remains on View_2() with the back button in navigation bar.
How can I make to show SearchView() and not keep the state of NavigationLink?
It's the default behavior. Attach id to TabView.
}//End TabView
.accentColor(Color("ColorMainDark"))
.id(appState.currentTab) //<--Here

SwiftUI NavigationView Not Fully Extending In View

I am working with NavigationView in SwiftUI and having an issue with it extending fully to the bottom of the screen.
I created a simple List in and this works fine. However, when I put it in a NavigationView, it creates a gray area at the bottom. I've tried adjusting the frame and a number of other things to no avail. I've never seen this before. Any help would be appreciated.
struct ListingView: View {
var body: some View {
List(0..<5) { item in
Text("Test")
}
}
}
struct ListingView: View {
var body: some View {
NavigationView {
List(0..<5) { item in
Text("Test")
}
}
}
}
struct ContentView: View {
// PacificBlue Background Set Up.
init() {
UITabBar.appearance().isTranslucent = false
UITabBar.appearance().barTintColor = UIColor(Color.pacificBlue)
}
// MARK: View
var body: some View {
TabView {
SeafoodListView()
.tabItem {
Image(systemName: "line.diagonal.arrow")
Text("Market")
}.tag(0) // SeafoodMarketView
ListingView()
.tabItem {
Image(systemName: "list.bullet.rectangle")
Text("Listings")
}.tag(1) // ListingView
RequestView()
.tabItem {
Image(systemName: "megaphone")
Text("Requests")
}.tag(2) // RequestView
MessengerView()
.tabItem {
Image(systemName: "ellipsis.bubble")
Text("Messenger")
}.tag(3) // MessengerView
AccountView()
.tabItem {
Image(systemName: "person")
Text("Account")
}.tag(4) // AccountView
} // TabView
.accentColor(.white)
}
}
// MARK: Preview
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
This is due to hack with appearance...
init() {
// UITabBar.appearance().isTranslucent = false // remove this line !!!
UITabBar.appearance().barTintColor = UIColor(Color.pacificBlue)
}
Alternate: replace entire appearance with configured opaque background
init() {
let newAppearance = UITabBarAppearance()
newAppearance.configureWithOpaqueBackground()
newAppearance.backgroundColor = UIColor(Color.pacificBlue)
UITabBar.appearance().standardAppearance = newAppearance
}

Disable item in TabView SwiftUI

How Can I set an item to disabled (not clickable) but visible in my tabView ?
TabView(selection: $selectedTab) {
Settings()
.tabItem {
Image(systemName: "gearshape.fill")
Text("Settings")
}.tag(1)
.disabled(true) // Not Working
I just create a way to do what you want fully supported and customisable!
test with Xcode Version 12.1, iOS 14.1, Here goes:
import SwiftUI
struct ContentView: View {
#State private var selection = 0
#State private var exSelection = 0
private var disableThis = 2
var body: some View
{
TabView(selection: $selection)
{
viewFinder(selectedIndex: selection == disableThis ? $exSelection : $selection)
.tabItem { Image(systemName: "1.circle") }
.tag(0)
viewFinder(selectedIndex: selection == disableThis ? $exSelection : $selection)
.tabItem { Image(systemName: "2.circle") }
.tag(1)
viewFinder(selectedIndex: selection == disableThis ? $exSelection : $selection)
.tabItem { Image(systemName: "3.circle") }
.tag(2)
viewFinder(selectedIndex: selection == disableThis ? $exSelection : $selection)
.tabItem { Image(systemName: "4.circle") }
.tag(3)
}
.onAppear()
{
UITabBar.appearance().barTintColor = .white
}
.accentColor(selection == disableThis ? Color.gray : Color.red)
.onChange(of: selection) { _ in
if selection != disableThis { exSelection = selection } else { selection = exSelection }
}
}
}
struct viewFinder: View
{
#Binding var selectedIndex: Int
var body: some View {
return Group
{
if selectedIndex == 0
{
FirstView()
}
else if selectedIndex == 1
{
SecondView()
}
else if selectedIndex == 2
{
ThirdView()
}
else if selectedIndex == 3
{
FourthView()
}
else
{
EmptyView()
}
}
}
}
struct FirstView: View { var body: some View {Text("FirstView")}}
struct SecondView: View { var body: some View {Text("SecondView")}}
struct ThirdView: View { var body: some View {Text("ThirdView")}}
struct FourthView: View { var body: some View {Text("FourthView")}}
There is not direct SwiftUI instrument for this now (SwiftUI 2.0), so find below possible approach based on TabBarAccessor from my another answer https://stackoverflow.com/a/59972635/12299030.
Tested with Xcode 12.1 / iOS 14.1 (note - tint color changed just for demo because disabled item is grey and invisible on grey tabbar)
struct TestTabBar: View {
init() {
UITabBar.appearance().unselectedItemTintColor = UIColor.green
}
#State private var selection = 0
var body: some View {
TabView(selection: $selection) {
Text("First View")
.background(TabBarAccessor { tabBar in
tabBar.items?.last?.isEnabled = false // << here !!
})
.tabItem { Image(systemName: "1.circle") }
.tag(0)
Text("Second View")
.tabItem { Image(systemName: "2.circle") }
.tag(1)
}
}
}