SwiftUI: How to update image to filled / outlined in TabView - swiftui

I'm trying to use filled image when it is selected and outlined image when it is deselected. I tried to render the images but still filled
So I thought this would work, but it doesn't:
struct ListTabView: View {
#State private var selectedTab = 0
var body: some View {
NavigationView {
TabView(selection: $selectedTab) {
Text("Tab 1")
.onTapGesture {
self.selectedTab += 1
}
.tabItem {
selectedTab == 0 ? Image(systemName: "star.fill") : Image(systemName: "star")
Text("First")
}
.tag(0)
Text("Tab 2")
.onTapGesture {
self.selectedTab -= 1
}
.tabItem {
selectedTab == 1 ? Image(systemName: "moon.stars.fill") : Image(systemName: "moon.stars")
Text("Second")
}
.tag(1)
}
.accentColor(.pink)
.onAppear {
UITabBar.appearance().barTintColor = .white
}
}
}
}
struct ListTabView_Previews: PreviewProvider {
static var previews: some View {
ListTabView()
}
}

Your code actually works. The issue is something else not documented that I can find. If you use a non .fill variant of an SF Font, the .fill variant will be substituted. Use the following code to test it:
TabView(selection: $selectedTab) {
VStack {
Text("Tab 1")
Text(Image(systemName: "star"))
}
.tabItem {
selectedTab == 0 ? Image(systemName: "star") : Image(systemName: "sun.max")
Text("First")
}
.tag(0)
VStack {
Text("Tab 2")
Text(Image(systemName: "moon.stars"))
}
.tabItem {
selectedTab == 1 ? Image(systemName: "moon.stars") : Image(systemName: "sun.max")
Text("Second")
}
.tag(1)
}
You will note I used plain variants, and yet the filled variant was used. Also, you don't need the .onTap(), but I suspect you added it when the images didn't seem to switch.

You can add this to Image / Label:
Image(systemName: selectedTab == 0 ? "star.fill" : "star")
.environment(\.symbolVariants, selectedTabItemIndex == 0 ? .fill : .none)
It will allow you to set the symbol variants as you would expect it.

Related

Show selected tab in TabView in SwiftUI

When using TabView in SwiftUI, what can I do to show the selected Tab like in the following picture?
I've tried creating a VStack within each tab like this:
struct ContentView: View {
#State public var tabViewSelection = 0
var body: some View {
TabView(selection: $tabViewSelection) {
HomeFirstLevel()
.tabItem {
VStack {
Image("HomeIcon")
Rectangle()
.frame(height: 7)
.foregroundColor((tabViewSelection == 0) ? .black : .clear)
}
}.tag(0)
}
}
}
But it's not working.
I can't even seem to add a Rectangle instead of an Image:
HomeFirstLevel()
.tabItem {
Rectangle()
}.tag(0)
Does TabView not accept shapes?
Thanks in advance for the help!
You can not set shape in tabItem. But you can use ZStack to add shape over the tab bar and set the x position.
Here is the demo.
struct ContentViewTabDemo: View {
#State public var tabViewSelection = 0
private var singleTabWidth = UIScreen.main.bounds.width / 5
var body: some View {
ZStack(alignment: .bottomLeading) {
TabView(selection: $tabViewSelection) {
Color.red
.tabItem {
VStack {
Image(systemName: "circle.fill")
}
}.tag(0)
Color.blue
.tabItem {
VStack {
Image(systemName: "heart.fill")
}
}.tag(1)
Color.red
.tabItem {
VStack {
Image(systemName: "circle.fill")
}
}.tag(2)
Color.blue
.tabItem {
VStack {
Image(systemName: "heart.fill")
}
}.tag(3)
Color.red
.tabItem {
VStack {
Image(systemName: "circle.fill")
}
}.tag(4)
}
Rectangle()
.offset(x: singleTabWidth * CGFloat(tabViewSelection))
.frame(width: singleTabWidth, height: 7)
.padding(.bottom, 2)
.animation(.default)
}
}
}

How to use different tab items for selected/unselected?

How can I make a different tab item for selected and unselected tabs? For example, I would like to use a different image and make the selected text bold.
This is what I have:
struct ContentView: View {
#SceneStorage("selectedTab") private var selectedTab = 0
var body: some View {
TabView(selection: $selectedTab) {
Text("Content 1")
.tabItem {
Label("First", systemImage: "alarm")
.accessibilityHint("Something 1")
}
Text("Content 2")
.tabItem {
Label("Second", systemImage: "calendar")
.accessibilityHint("Something 2")
}
}
}
}
Is there a way a built in way to do this since inside the tab I can't figure out if it is the selected one or not.
Use selectedTab with tag and change your tab image by using the selectedTab condition.
And for Font you can use UITabBarAppearance().
struct ContentView: View {
#State private var selectedTab = 0
init() {
// Set font here of selected and normal
let appearance = UITabBarAppearance()
appearance.stackedLayoutAppearance.normal.titleTextAttributes = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 10)]
appearance.stackedLayoutAppearance.selected.titleTextAttributes = [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 15)]
UITabBar.appearance().standardAppearance = appearance
}
var body: some View {
TabView(selection: $selectedTab) {
Text("Content 1")
.tabItem {
Label("First", systemImage: selectedTab == 0 ? "alarm" : "alarm_unselected") //<-- Here
.accessibilityHint("Something 1")
}.tag(0) //<-- Here
Text("Content 2")
.tabItem {
Label("Second", systemImage: selectedTab == 1 ? "calendar" : "calendar_unselected") //<-- Here
.accessibilityHint("Something 2")
}.tag(1) //<-- Here
}
}
}

Error creating a custom PageView in SwiftUI 2

I am working on an app that requires 6 items in a PageView, xcode was acting up so i came on Stack Overflow and found pawello2222's way, found it really helpful but I still need to connect it to the horizontal links on top. here is the code, thanks a million.
Original solution: How can I implement PageView in SwiftUI?
Below is my code and what I want to achieve, swiping left or right works, but clicking on the links does not change the view
struct TestingView: View {
#State var selection = 0
var body: some View {
VStack {
HStack(spacing: 10) {
VStack {
Text("Link 1")
.foregroundColor(self.selection == 0 ? Color.blue : Color("Silver").opacity(0.7))
.font(.caption)
.fontWeight(.bold)
.clipShape(Rectangle())
.onTapGesture {
withAnimation(.default) {
self.selection = 0
}
}
}
Spacer(minLength: 0)
VStack {
Text("Link 2")
.foregroundColor(self.selection == 1 ? Color.blue : Color("Silver").opacity(0.7))
.font(.caption)
.fontWeight(.bold)
.clipShape(Rectangle())
.onTapGesture {
withAnimation(.default) {
self.selection = 1
}
}
}
Spacer(minLength: 0)
VStack {
Text("Link 3")
.foregroundColor(self.selection == 2 ? Color.blue : Color("Silver").opacity(0.7))
.font(.caption)
.fontWeight(.bold)
.clipShape(Rectangle())
.onTapGesture {
withAnimation(.default) {
self.selection = 2
}
}
}
}
PageView(selection: $selection, indexDisplayMode: .never, indexBackgroundDisplayMode: .never) {
VStack {
FirstView()
}
.tag(0)
VStack {
SecondView()
}
.tag(1)
VStack {
ThirdView()
}
.tag(2)
}
}
}
}

Show TabView elements in Touch Bar - SwiftUI

I'm working on a Mac app (via Mac Catalyst), and I'm looking for a way to display TabView items in the Touch Bar as well...
I tried with the .touchBar modifier, with the targetEnvironment(macCatalyst) and also with #if os(macOS), but no luck...
Any suggestions?
Here is my code:
import SwiftUI
let furl = URL(fileURLWithPath: "path")
struct ContentView: View {
#State private var selected = 0
#State private var isActive = false
var body: some View {
TabView(selection: $selected) {
NavigationView {
HomeView()
}
.navigationViewStyle(StackNavigationViewStyle())
.tabItem {
Image(systemName: (selected == 0 ? "house.fill" : "house"))
Text("Home")
}.tag(0)
NavigationView {
CategoryView(dm: DownloadManager())
}
.navigationViewStyle(DoubleColumnNavigationViewStyle())
.tabItem {
Image(systemName: (selected == 1 ? "text.justify" : "text.justify"))
Text("Categorie")
}.tag(1)
NavigationView {
GalleryView(dm: DownloadManager())
}
.navigationViewStyle(DoubleColumnNavigationViewStyle())
.tabItem {
Image(systemName: (selected == 2 ? "photo.fill" : "photo"))
Text("Galleria")
}.tag(2)
NavigationView {
FavoritesView()
}
.navigationViewStyle(DoubleColumnNavigationViewStyle())
.tabItem {
Image(systemName: (selected == 3 ? "star.fill" : "star"))
Text("Preferiti")
}.tag(3)
NavigationView {
InfoView()
}
.navigationViewStyle(StackNavigationViewStyle())
.tabItem {
Image(systemName: (selected == 4 ? "info.circle.fill" : "info.circle"))
Text("Informazioni")
}.tag(4)
}
.accentColor(.white)
.onAppear() {
UINavigationBar.appearance().barTintColor = UIColor(red: 112.0/255.0, green: 90.0/255.0, blue: 143.0/255.0, alpha: 1.0)
UITabBar.appearance().barTintColor = UIColor(red: 112.0/255.0, green: 90.0/255.0, blue: 143.0/255.0, alpha: 1.0)
UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
}
}
}
Thank you!

Change Tabbar Icon Image SwiftUI

I want to change tabItem icon image when tapped on one of the tabItem in this code. How can it be done?
var body: some View {
ZStack {
TabView(selection:$selection) {
OffersView()
.tabItem ({
Image(systemName: "bag").renderingMode(.template)
Text("Offers")
})
.tag(1)
StepView()
.tabItem ({
Image(systemName: "figure.walk.circle").renderingMode(.template)
Text("Steps")
})
.tag(2)
ProfileView()
.tabItem {
Image(systemName: "person")
Text("Profile")
}
.tag(3)
}
.accentColor(Color("ColorOnboarding"))
.navigationBarBackButtonHidden(true)
}
You can change image like this,
var body: some View {
ZStack {
TabView(selection:$selection) {
OffersView()
.tabItem ({
Image(systemName: selection == 1 ? "bag" : "bag2").renderingMode(.template)
Text("Offers")
})
.tag(1)
StepView()
.tabItem ({
Image(systemName: selection == 2 ? "figure.walk.circle" : "figure.walk.circle2").renderingMode(.template)
Text("Steps")
})
.tag(2)
// -----Other Code-----
You can use state for it
var body: some View {
#State var isTapped = false
ZStack {
TabView(selection:$isTapped) {
OffersView()
.tabItem ({
Image(systemName: selection == 1 ? "bag" : "bag2").renderingMode(.template)
Text("Offers")
})
.tag(1)
StepView()
.tabItem ({
Image(systemName: selection == 2 ? "figure.walk.circle" : "figure.walk.circle2").renderingMode(.template)
Text("Steps")
})
.tag(2)
ProfileView()
.tabItem {
Image(systemName: "person")
Text("Profile")
}
.tag(3)
}
.accentColor(Color("ColorOnboarding"))
.navigationBarBackButtonHidden(true)
}