Show TabView elements in Touch Bar - SwiftUI - 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!

Related

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

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.

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)
}
}
}

Can't change background color for Navigation Bar in Double Column (SwiftUI)

I've been trying for several hours to change the color of the Navigation Bar in my app... It's a little better than before, because I added the "isTranslucent" parameter, so now the Navigation Bar is gray (before this, it was completely white), but I still can't set it to the same color as the sidebar, and especially with the same height: the height becomes the same only when I press an element in the sidebar...
Here's what happens before I tap on a sidebar element:
Before tap
And here after I tapped it:
After tap
Here's the 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 {
SearchView()
}
.navigationViewStyle(DoubleColumnNavigationViewStyle())
.tabItem {
Image(systemName: (selected == 3 ? "magnifyingglass" : "magnifyingglass"))
Text("Ricerca")
}.tag(3)
NavigationView {
FavoritesView()
}
.navigationViewStyle(DoubleColumnNavigationViewStyle())
.tabItem {
Image(systemName: (selected == 4 ? "star.fill" : "star"))
Text("Preferiti")
}.tag(4)
}
.accentColor(.white)
.onAppear() {
UINavigationBar.appearance().isTranslucent = false
UINavigationBar.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]
UITabBar.appearance().barTintColor = UIColor(red: 112.0/255.0, green: 90.0/255.0, blue: 143.0/255.0, alpha: 1.0)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Please help, I'm going crazy from trying! Thank you!

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)
}
}
}

TabView tabItem image move to top

I learned how to create a tabBar like UIKit tabBar in swiftUI. And I want to move the center tabItem to top . Is there any way I can achieve this?
TabView code
TabView {
ViewTasks()
.tabItem {
Image(systemName: "list.bullet.below.rectangle")
Text("View Tasks")
}
AddTask()
.tabItem {
Image(systemName: "plus.circle").font(.system(size: 60))
}
CategoriesTasks()
.tabItem {
Image(systemName: "square.grid.2x2")
Text("Categories")
}
}
Visual Example
First idea is to use ZStack so you can cover tabItem with your own tappable image. Here is example:
struct TabViewModel: View {
#State var showActionSheet: Bool = false
var body: some View {
ZStack {
GeometryReader { geometry in
TabView {
Text("list")
.tabItem {
Image(systemName: "list.bullet.below.rectangle")
}
Text("plus")
.tabItem {
Text(" ")
}
Text("categories")
.tabItem {
Image(systemName: "square.grid.2x2")
}
}
Image(systemName: "plus.circle")
.resizable()
.frame(width: 40, height: 40)
.shadow(color: .gray, radius: 2, x: 0, y: 5)
.offset(x: geometry.size.width / 2 - 20, y: geometry.size.height - 80)
.onTapGesture {
self.showActionSheet.toggle()
}
}
}
.actionSheet(isPresented: $showActionSheet) {
ActionSheet(title: Text("some actions"))
}
}
}
so some image will cover center tabView item, which will be invisible (Text(" ")):
update
if you still need to switch between these 3 views you can use #State var selection (don't forget to tag(...) tabItems):
struct TabViewModel: View {
#State var selection: Int = 0
var body: some View {
ZStack {
GeometryReader { geometry in
TabView(selection: self.$selection) {
//...
Text("plus")
.tabItem {
Text(" ")
}.tag(1)
//...
.onTapGesture {
self.selection = 1
}
// ...
}
SWIFTUI 2
.onTapGesture usage sometimes causes unexpected behavior such as not displaying the overlay view (alert, sheets or fullscreen) or displaying it when you click another tab. The safer way is to set the selection value with the .onChange(of:) method:
struct TabViewModel: View {
#State var selection: Int = 0
var body: some View {
ZStack {
GeometryReader { geometry in
TabView(selection: self.$selection) {
//...
Text("plus")
.tabItem {
Text(" ")
}.tag(1)
//...
.onChange(of: selection) { _ in
self.selection = 1
}
// ...
}